Mercurial > hg > forks > bilotrip-mj12
comparison liboggplayer-src/src/play.cpp @ 2:105513a2e3c9
Import liboggplayer source.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 05 Aug 2013 13:50:20 +0300 |
parents | |
children | 083c73ceb716 |
comparison
equal
deleted
inserted
replaced
1:3562f296deb0 | 2:105513a2e3c9 |
---|---|
1 #include "imp.hpp" | |
2 | |
3 bool OggPlayer::Imp::ready() { | |
4 return audio_cache_ready; | |
5 } | |
6 // return true if need more data | |
7 // the return value is strange but the function is | |
8 // for internal use only and should only be called | |
9 // in play() | |
10 bool OggPlayer::Imp::decode_audio() { | |
11 int ret; | |
12 float **pcm; | |
13 // if there's pending, decoded audio, grab it | |
14 while ((ret = vorbis_synthesis_pcmout(&v_state, &pcm)) > 0) { | |
15 boost::unique_lock<boost::mutex> lock(audio_mut); | |
16 // first we need to convert from float to signed short | |
17 // then we will use SDL_ConvertAudio | |
18 // is our temp buffer big enough? | |
19 if (cirbuf.capacity() < ret * v_info.channels * cvt.len_mult | |
20 * sizeof(short)) { | |
21 cirbuf.set_capacity(ret * v_info.channels * cvt.len_mult * 16 | |
22 * sizeof(short)); | |
23 } | |
24 if (cirbuf.capacity() - cirbuf.size() < ret * v_info.channels | |
25 * cvt.len_mult * sizeof(short)) { | |
26 audio_cache_ready = true; | |
27 return false; | |
28 } | |
29 if ((audio_buffer_size) < ret * v_info.channels * cvt.len_mult | |
30 * sizeof(short)) { | |
31 if (audio_buffer) | |
32 delete[] audio_buffer; | |
33 audio_buffer_size = ret * v_info.channels * cvt.len_mult | |
34 * sizeof(short); | |
35 audio_buffer = new char[audio_buffer_size]; | |
36 } | |
37 // convert from float to short | |
38 int k = 0; | |
39 char* char_ab = (char*) audio_buffer; | |
40 short* short_ab = (short*) audio_buffer; | |
41 for (int i = 0; i < ret; i++) { | |
42 for (int j = 0; j < v_info.channels; j++) { | |
43 int val = (int)(pcm[j][i] * 32767.f); | |
44 if (val > 32767) | |
45 val = 32767; | |
46 if (val < -32768) | |
47 val = -32768; | |
48 short_ab[k++] = val; | |
49 | |
50 } | |
51 } | |
52 vorbis_synthesis_read(&v_state, ret); | |
53 // now we can use SDL_ConvertAudio | |
54 cvt.len = k * sizeof(short); | |
55 cvt.buf = (Uint8*) char_ab; | |
56 SDL_ConvertAudio(&cvt); | |
57 | |
58 for (int i = 0; i < cvt.len_cvt; i++) { | |
59 cirbuf.push_back(char_ab[i]); | |
60 } | |
61 | |
62 | |
63 if(v_state.granulepos!=0){ | |
64 AudioGranulePos agp; | |
65 agp.pos = audio_bytes_played+cvt.len_cvt; | |
66 agp.set_time = (double)v_state.granulepos/(double)v_info.rate; | |
67 audio_granule_poses.push_back(agp); | |
68 } | |
69 | |
70 lock.unlock(); | |
71 audio_ready_cond.notify_one(); | |
72 return false; | |
73 | |
74 } | |
75 // no pending audio; is there a pending packet to decode? | |
76 if (ogg_stream_packetout(&o_vsstate, &o_packet) > 0) { | |
77 if (vorbis_synthesis(&v_block, &o_packet) == 0) { | |
78 vorbis_synthesis_blockin(&v_state, &v_block); | |
79 return false; | |
80 } | |
81 } else { return true; } | |
82 | |
83 } | |
84 // similar to decode_audio | |
85 bool OggPlayer::Imp::decode_video() { | |
86 bool was_ready=videobuf_ready; | |
87 boost::unique_lock<boost::mutex> lock(video_mut, boost::defer_lock); | |
88 ogg_int64_t videobuf_granulepos = -1; | |
89 if (!videobuf_ready){ | |
90 if(!lock.try_lock()) | |
91 return false; | |
92 } | |
93 while (!videobuf_ready) { | |
94 // theora is one in, one out... | |
95 if (ogg_stream_packetout(&o_tsstate, &o_packet) > 0) { | |
96 | |
97 if(pp_inc){ | |
98 pp_level+=pp_inc; | |
99 theora_control(&t_state,TH_DECCTL_SET_PPLEVEL,&pp_level,sizeof(pp_level)); | |
100 pp_inc=0; | |
101 } | |
102 if (o_packet.granulepos >= 0) { | |
103 theora_control(&t_state, TH_DECCTL_SET_GRANPOS, | |
104 &o_packet.granulepos, sizeof(o_packet.granulepos)); | |
105 } | |
106 if (theora_decode_packetin(&t_state, &o_packet) == 0) { | |
107 videobuf_granulepos = t_state.granulepos; | |
108 videobuf_time = theora_granule_time(&t_state, videobuf_granulepos); | |
109 | |
110 if (videobuf_time >= get_time()){ | |
111 videobuf_ready = true; | |
112 frame++; | |
113 } | |
114 else { | |
115 // If we are too slow, reduce the pp level. | |
116 pp_inc=pp_level>0?-1:0; | |
117 } | |
118 } | |
119 | |
120 } else | |
121 break; | |
122 } | |
123 lock.unlock(); | |
124 if(videobuf_ready!=was_ready) | |
125 video_ready_cond.notify_one(); | |
126 | |
127 return !videobuf_ready; | |
128 } | |
129 | |
130 void OggPlayer::Imp::play_loop() { | |
131 if(!file_in.is_open()) return; | |
132 audio_cache_ready = false; | |
133 audio_bytes_played = 0; | |
134 bool audio_need_data = vorbis_p; | |
135 bool video_need_data = theora_p; | |
136 timer.restart(); | |
137 // buffer_data() will close the file on eof | |
138 while ((file_in.is_open() || !audio_need_data || !video_need_data) && playing) { | |
139 | |
140 // sync audio video timer | |
141 while(!audio_granule_poses.empty() && | |
142 audio_granule_poses.front().pos <= audio_bytes_played){ | |
143 time_factor= audio_granule_poses.front().set_time/timer.elapsed(); | |
144 audio_granule_poses.pop_front(); | |
145 } | |
146 | |
147 if (theora_p && !videobuf_ready) { | |
148 video_need_data = decode_video(); | |
149 } | |
150 | |
151 if (vorbis_p) { | |
152 audio_need_data = decode_audio(); | |
153 } | |
154 | |
155 // are we at or past time for this video frame? | |
156 if (videobuf_ready && videobuf_time <= get_time()) { | |
157 videobuf_ready = false; | |
158 } | |
159 // if no data yet for somebody, grab another page | |
160 if (file_in.is_open() && (audio_need_data || video_need_data)) { | |
161 // buffer_data() can handle eof itself | |
162 buffer_data(); | |
163 while (ogg_sync_pageout(&o_sync, &o_page) > 0) { | |
164 queue_page(&o_page); | |
165 } | |
166 audio_need_data = false; | |
167 video_need_data = false; | |
168 } | |
169 } | |
170 playing = false; | |
171 | |
172 // do not risk a lock | |
173 audio_ready_cond.notify_one(); | |
174 video_ready_cond.notify_one(); | |
175 | |
176 // cleanup | |
177 close(); | |
178 } | |
179 | |
180 void OggPlayer::Imp::play() { | |
181 playing = true; | |
182 play_thread = boost::thread(boost::bind(&OggPlayer::Imp::play_loop, this)); | |
183 } | |
184 |