2
|
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
|