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