Mercurial > mplayer.hg
comparison libmpdemux/demux_asf.c @ 23239:cc01eab9f3a9
For DVR-MS:
extract timing information from the payload extension, set key frames,
detect video frame boundaries, interpolate the average video frame time
using the known informations from past frames and timestamps.
Video data before the first video key frame is thrown away.
Patch by John Donaghy johnfdonaghy gmail com
author | nicodvb |
---|---|
date | Mon, 07 May 2007 21:58:42 +0000 |
parents | 4d81dbdf46b9 |
children | ab885f928444 |
comparison
equal
deleted
inserted
replaced
23238:dc442598a7d8 | 23239:cc01eab9f3a9 |
---|---|
64 //if(i<len) memcpy(dst+i,src+i,len-i); | 64 //if(i<len) memcpy(dst+i,src+i,len-i); |
65 free(*src); | 65 free(*src); |
66 *src = dst; | 66 *src = dst; |
67 } | 67 } |
68 | 68 |
69 /***************************************************************** | |
70 * \brief initializes asf private data | |
71 * | |
72 */ | |
73 static void init_priv (struct asf_priv* asf){ | |
74 asf->last_vid_seq=-1; | |
75 asf->vid_ext_timing_index=-1; | |
76 asf->aud_ext_timing_index=-1; | |
77 asf->vid_ext_frame_index=-1; | |
78 } | |
79 | |
69 #ifdef USE_LIBAVCODEC_SO | 80 #ifdef USE_LIBAVCODEC_SO |
70 #include <ffmpeg/avcodec.h> | 81 #include <ffmpeg/avcodec.h> |
71 #elif defined(USE_LIBAVCODEC) | 82 #elif defined(USE_LIBAVCODEC) |
72 #include "libavcodec/avcodec.h" | 83 #include "libavcodec/avcodec.h" |
73 #else | 84 #else |
147 memset(dp->buffer+dp->len+len, 0, FF_INPUT_BUFFER_PADDING_SIZE); | 158 memset(dp->buffer+dp->len+len, 0, FF_INPUT_BUFFER_PADDING_SIZE); |
148 mp_dbg(MSGT_DEMUX,MSGL_DBG4,"data appended! %d+%d\n",dp->len,len); | 159 mp_dbg(MSGT_DEMUX,MSGL_DBG4,"data appended! %d+%d\n",dp->len,len); |
149 dp->len+=len; | 160 dp->len+=len; |
150 } | 161 } |
151 | 162 |
152 static int demux_asf_read_packet(demuxer_t *demux,unsigned char *data,int len,int id,int seq,unsigned long time,unsigned short dur,int offs,int keyframe){ | 163 static int demux_asf_read_packet(demuxer_t *demux,unsigned char *data,int len,int id,int seq,uint64_t time,unsigned short dur,int offs,int keyframe){ |
153 struct asf_priv* asf = demux->priv; | 164 struct asf_priv* asf = demux->priv; |
154 demux_stream_t *ds=NULL; | 165 demux_stream_t *ds=NULL; |
155 int close_seg=0; | 166 int close_seg=0; |
156 int frame_end_pos=END_NOT_FOUND; | |
157 | 167 |
158 mp_dbg(MSGT_DEMUX,MSGL_DBG4,"demux_asf.read_packet: id=%d seq=%d len=%d\n",id,seq,len); | 168 mp_dbg(MSGT_DEMUX,MSGL_DBG4,"demux_asf.read_packet: id=%d seq=%d len=%d\n",id,seq,len); |
159 | 169 |
160 if(demux->video->id==-1) | 170 if(demux->video->id==-1) |
161 if(demux->v_streams[id]) | 171 if(demux->v_streams[id]) |
185 if(ds){ | 195 if(ds){ |
186 if(ds->asf_packet){ | 196 if(ds->asf_packet){ |
187 demux_packet_t* dp=ds->asf_packet; | 197 demux_packet_t* dp=ds->asf_packet; |
188 | 198 |
189 if (ds==demux->video && asf->asf_is_dvr_ms) { | 199 if (ds==demux->video && asf->asf_is_dvr_ms) { |
190 frame_end_pos=mpeg1_find_frame_end(demux, data, len); | 200 if (asf->new_vid_frame_seg) { |
191 | |
192 if (frame_end_pos != END_NOT_FOUND) { | |
193 dp->pos=demux->filepos; | 201 dp->pos=demux->filepos; |
194 if (frame_end_pos > 0) { | |
195 demux_asf_append_to_packet(dp,data,frame_end_pos,offs); | |
196 data += frame_end_pos; | |
197 len -= frame_end_pos; | |
198 } | |
199 close_seg = 1; | 202 close_seg = 1; |
200 if (asf->avg_vid_frame_time > 0.0 ) { | |
201 // correct the pts for the packet | |
202 // because dvr-ms files do not contain accurate | |
203 // pts values but we can deduce them using | |
204 // the average frame time | |
205 if (asf->dvr_last_vid_pts > 0.0) | |
206 dp->pts=asf->dvr_last_vid_pts+asf->avg_vid_frame_time; | |
207 asf->dvr_last_vid_pts = dp->pts; | |
208 } | |
209 } else seq = ds->asf_seq; | 203 } else seq = ds->asf_seq; |
210 } else close_seg = ds->asf_seq!=seq; | 204 } else close_seg = ds->asf_seq!=seq; |
211 | 205 |
212 if(close_seg){ | 206 if(close_seg){ |
213 // closed segment, finalize packet: | 207 // closed segment, finalize packet: |
229 mp_msg(MSGT_DEMUX,MSGL_V,"warning! broken fragment, %d bytes missing \n",offs); | 223 mp_msg(MSGT_DEMUX,MSGL_V,"warning! broken fragment, %d bytes missing \n",offs); |
230 return 0; | 224 return 0; |
231 } | 225 } |
232 dp=new_demux_packet(len); | 226 dp=new_demux_packet(len); |
233 memcpy(dp->buffer,data,len); | 227 memcpy(dp->buffer,data,len); |
234 dp->pts=time*0.001f; | 228 if (asf->asf_is_dvr_ms) |
229 dp->pts=time*0.0000001f; | |
230 else | |
231 dp->pts=time*0.001f; | |
235 dp->flags=keyframe; | 232 dp->flags=keyframe; |
236 // if(ds==demux->video) printf("ASF time: %8d dur: %5d \n",time,dur); | 233 // if(ds==demux->video) printf("ASF time: %8d dur: %5d \n",time,dur); |
237 dp->pos=demux->filepos; | 234 dp->pos=demux->filepos; |
238 ds->asf_packet=dp; | 235 ds->asf_packet=dp; |
239 ds->asf_seq=seq; | 236 ds->asf_seq=seq; |
243 } | 240 } |
244 | 241 |
245 return 0; | 242 return 0; |
246 } | 243 } |
247 | 244 |
245 /***************************************************************** | |
246 * \brief read the replicated data associated with each segment | |
247 * \parameter pp reference to replicated data | |
248 * \parameter id stream number | |
249 * \parameter seq media object number | |
250 * \parameter keyframe key frame indicator - set to zero if keyframe, non-zero otherwise | |
251 * \parameter seg_time set to payload time when valid, if audio or new video frame payload, zero otherwise | |
252 * | |
253 */ | |
254 static void get_payload_extension_data(demuxer_t *demux, unsigned char** pp, unsigned char id, unsigned int seq, int *keyframe, uint64_t *seg_time){ | |
255 struct asf_priv* asf = demux->priv; | |
256 uint64_t payload_time; //100ns units | |
257 int i, ext_max, ext_timing_index; | |
258 uint8_t *pi = *pp+4; | |
259 | |
260 if(demux->video->id==-1) | |
261 if(demux->v_streams[id]) | |
262 demux->video->id=id; | |
263 | |
264 if(demux->audio->id==-1) | |
265 if(demux->a_streams[id]) | |
266 demux->audio->id=id; | |
267 | |
268 if (id!=demux->video->id && id!=demux->audio->id) return; | |
269 | |
270 if (id==demux->video->id) { | |
271 ext_max = asf->vid_repdata_count; | |
272 ext_timing_index = asf->vid_ext_timing_index; | |
273 } else { | |
274 ext_max = asf->aud_repdata_count; | |
275 ext_timing_index = asf->aud_ext_timing_index; | |
276 } | |
277 | |
278 *seg_time=0.0; | |
279 asf->new_vid_frame_seg = 0; | |
280 | |
281 for (i=0; i<ext_max; i++) { | |
282 uint16_t payextsize; | |
283 uint8_t segment_marker; | |
284 | |
285 if (id==demux->video->id) | |
286 payextsize = asf->vid_repdata_sizes[i]; | |
287 else | |
288 payextsize = asf->aud_repdata_sizes[i]; | |
289 | |
290 if (payextsize == 65535) { | |
291 payextsize = LOAD_LE16(pi); | |
292 pi+=2; | |
293 } | |
294 | |
295 // if this is the timing info extension then read the payload time | |
296 if (i == ext_timing_index) | |
297 payload_time = (uint64_t) LOAD_LE32(pi+8) | (uint64_t)LOAD_LE32(pi+8 + 4) << 32; | |
298 | |
299 // if this is the video frame info extension then | |
300 // set the keyframe indicator, the 'new frame segment' indicator | |
301 // and (initially) the 'frame time' | |
302 if (i == asf->vid_ext_frame_index && id==demux->video->id) { | |
303 segment_marker = pi[0]; | |
304 // Known video stream segment_marker values that | |
305 // contain useful information: | |
306 // | |
307 // NTSC/ATSC (29.97fps): 0X4A 01001010 | |
308 // 0X4B 01001011 | |
309 // 0X49 01001001 | |
310 // | |
311 // PAL/ATSC (25fps): 0X3A 00111010 | |
312 // 0X3B 00111011 | |
313 // 0X39 00111001 | |
314 // | |
315 // ATSC progressive (29.97fps): 0X7A 01111010 | |
316 // 0X7B 01111011 | |
317 // 0X79 01111001 | |
318 // 11111111 | |
319 // ^ this is new video frame marker | |
320 // | |
321 // ^^^^ these bits indicate the framerate | |
322 // 0X4 is 29.97i, 0X3 is 25i, 0X7 is 29.97p, ???=25p | |
323 // | |
324 // ^^^ these bits indicate the frame type: | |
325 // 001 means I-frame | |
326 // 010 and 011 probably mean P and B | |
327 | |
328 asf->new_vid_frame_seg = (0X08 & segment_marker) && seq != asf->last_vid_seq; | |
329 | |
330 if (asf->new_vid_frame_seg) asf->last_vid_seq = seq; | |
331 | |
332 if (asf->avg_vid_frame_time == 0) { | |
333 // set the average frame time initially (in 100ns units). | |
334 // This is based on what works for known samples. | |
335 // It can be extended if more samples of different types can be obtained. | |
336 if (((segment_marker & 0XF0) >> 4) == 4) { | |
337 asf->avg_vid_frame_time = (uint64_t)((1.001 / 30.0) * 10000000.0); | |
338 asf->know_frame_time=1; | |
339 } else if (((segment_marker & 0XF0) >> 4) == 3) { | |
340 asf->avg_vid_frame_time = (uint64_t)(0.04 * 10000000.0); | |
341 asf->know_frame_time=1; | |
342 } else if (((segment_marker & 0XF0) >> 4) == 6) { | |
343 asf->avg_vid_frame_time = (uint64_t)(0.02 * 10000000.0); | |
344 asf->know_frame_time=1; | |
345 } else if (((segment_marker & 0XF0) >> 4) == 7) { | |
346 asf->avg_vid_frame_time = (uint64_t)((1.001 / 60.0) * 10000000.0); | |
347 asf->know_frame_time=1; | |
348 } else { | |
349 // we dont know the frame time initially so | |
350 // make a guess and then recalculate as we go. | |
351 asf->avg_vid_frame_time = (uint64_t)((1.001 / 60.0) * 10000000.0); | |
352 asf->know_frame_time=0; | |
353 } | |
354 } | |
355 *keyframe = (asf->new_vid_frame_seg && (segment_marker & 0X07) == 1); | |
356 } | |
357 pi +=payextsize; | |
358 } | |
359 | |
360 if (id==demux->video->id && asf->new_vid_frame_seg) { | |
361 asf->vid_frame_ct++; | |
362 // Some samples only have timings on key frames and | |
363 // the rest contain non-cronological timestamps. Interpolating | |
364 // the values between key frames works for all samples. | |
365 if (*keyframe) { | |
366 asf->found_first_key_frame=1; | |
367 if (!asf->know_frame_time && asf->last_key_payload_time > 0) { | |
368 // We dont know average frametime so recalculate. | |
369 // Giving precedence to the 'weight' of the existing | |
370 // average limits damage done to new value when there is | |
371 // a sudden time jump which happens occasionally. | |
372 asf->avg_vid_frame_time = | |
373 (0.9 * asf->avg_vid_frame_time) + | |
374 (0.1 * ((payload_time - asf->last_key_payload_time) / asf->vid_frame_ct)); | |
375 } | |
376 asf->last_key_payload_time = payload_time; | |
377 asf->vid_frame_ct = 1; | |
378 *seg_time = payload_time; | |
379 } else | |
380 *seg_time = (asf->last_key_payload_time + (asf->avg_vid_frame_time * (asf->vid_frame_ct-1))); | |
381 } | |
382 | |
383 if (id==demux->audio->id) { | |
384 if (payload_time != -1) | |
385 asf->last_aud_diff = payload_time - asf->last_aud_pts; | |
386 asf->last_aud_pts += asf->last_aud_diff; | |
387 *seg_time = asf->last_aud_pts; | |
388 } | |
389 } | |
248 //static int num_elementary_packets100=0; | 390 //static int num_elementary_packets100=0; |
249 //static int num_elementary_packets101=0; | 391 //static int num_elementary_packets101=0; |
250 | 392 |
251 // return value: | 393 // return value: |
252 // 0 = EOF or no stream found | 394 // 0 = EOF or no stream found |
355 unsigned int seq; | 497 unsigned int seq; |
356 unsigned int x; // offset or timestamp | 498 unsigned int x; // offset or timestamp |
357 unsigned int rlen; | 499 unsigned int rlen; |
358 // | 500 // |
359 int len; | 501 int len; |
360 unsigned int time2=0; | 502 uint64_t time2=0; |
361 int keyframe=0; | 503 int keyframe=0; |
362 | 504 |
363 if(p>=p_end) { | 505 if(p>=p_end) { |
364 mp_msg(MSGT_DEMUX,MSGL_V,"Warning! invalid packet 1, aborting parsing...\n"); | 506 mp_msg(MSGT_DEMUX,MSGL_V,"Warning! invalid packet 1, aborting parsing...\n"); |
365 break; | 507 break; |
409 break; | 551 break; |
410 default: | 552 default: |
411 if(rlen>=8){ | 553 if(rlen>=8){ |
412 p+=4; // skip object size | 554 p+=4; // skip object size |
413 time2=LOAD_LE32(p); // read PTS | 555 time2=LOAD_LE32(p); // read PTS |
556 if (asf->asf_is_dvr_ms) | |
557 get_payload_extension_data(demux, &p, streamno, seq, &keyframe, &time2); | |
414 p+=rlen-4; | 558 p+=rlen-4; |
415 } else { | 559 } else { |
416 mp_msg(MSGT_DEMUX,MSGL_V,"unknown segment type (rlen): 0x%02X \n",rlen); | 560 mp_msg(MSGT_DEMUX,MSGL_V,"unknown segment type (rlen): 0x%02X \n",rlen); |
417 time2=0; // unknown | 561 time2=0; // unknown |
418 p+=rlen; | 562 p+=rlen; |
455 } | 599 } |
456 break; | 600 break; |
457 default: | 601 default: |
458 // NO GROUPING: | 602 // NO GROUPING: |
459 //printf("fragment offset: %d \n",sh->x); | 603 //printf("fragment offset: %d \n",sh->x); |
460 demux_asf_read_packet(demux,p,len,streamno,seq,time2,duration,x,keyframe); | 604 if (!asf->asf_is_dvr_ms || asf->found_first_key_frame) |
605 demux_asf_read_packet(demux,p,len,streamno,seq,time2,duration,x,keyframe); | |
461 p+=len; | 606 p+=len; |
462 break; | 607 break; |
463 } | 608 } |
464 | 609 |
465 } // for segs | 610 } // for segs |
553 sh_audio_t *sh_audio=NULL; | 698 sh_audio_t *sh_audio=NULL; |
554 sh_video_t *sh_video=NULL; | 699 sh_video_t *sh_video=NULL; |
555 | 700 |
556 //---- ASF header: | 701 //---- ASF header: |
557 if(!asf) return NULL; | 702 if(!asf) return NULL; |
703 init_priv(asf); | |
558 if (!read_asf_header(demuxer,asf)) { | 704 if (!read_asf_header(demuxer,asf)) { |
559 free(asf); | 705 free(asf); |
560 return NULL; | 706 return NULL; |
561 } | 707 } |
562 stream_reset(demuxer->stream); | 708 stream_reset(demuxer->stream); |
568 mp_msg(MSGT_DEMUXER,MSGL_WARN,"ASF: " MSGTR_MissingVideoStream); | 714 mp_msg(MSGT_DEMUXER,MSGL_WARN,"ASF: " MSGTR_MissingVideoStream); |
569 demuxer->video->sh=NULL; | 715 demuxer->video->sh=NULL; |
570 //printf("ASF: missing video stream!? contact the author, it may be a bug :(\n"); | 716 //printf("ASF: missing video stream!? contact the author, it may be a bug :(\n"); |
571 } else { | 717 } else { |
572 sh_video=demuxer->video->sh;sh_video->ds=demuxer->video; | 718 sh_video=demuxer->video->sh;sh_video->ds=demuxer->video; |
573 //sh_video->fps=1000.0f; sh_video->frametime=0.001f; // 1ms - now set when reading asf header | 719 sh_video->fps=1000.0f; sh_video->frametime=0.001f; |
574 //sh_video->i_bps=10*asf->packetsize; // FIXME! | 720 //sh_video->i_bps=10*asf->packetsize; // FIXME! |
575 | 721 |
576 if (asf->asf_is_dvr_ms) { | 722 if (asf->asf_is_dvr_ms) { |
577 sh_video->bih->biWidth = 0; | 723 sh_video->bih->biWidth = 0; |
578 sh_video->bih->biHeight = 0; | 724 sh_video->bih->biHeight = 0; |
594 demuxer->seekable=0; | 740 demuxer->seekable=0; |
595 | 741 |
596 return demuxer; | 742 return demuxer; |
597 } | 743 } |
598 | 744 |
745 | |
746 static void demux_close_asf(demuxer_t *demuxer) { | |
747 struct asf_priv* asf = demuxer->priv; | |
748 | |
749 if (!asf) return; | |
750 | |
751 if (asf->aud_repdata_sizes) | |
752 free(asf->aud_repdata_sizes); | |
753 | |
754 if (asf->vid_repdata_sizes) | |
755 free(asf->vid_repdata_sizes); | |
756 | |
757 free(asf); | |
758 } | |
599 | 759 |
600 demuxer_desc_t demuxer_desc_asf = { | 760 demuxer_desc_t demuxer_desc_asf = { |
601 "ASF demuxer", | 761 "ASF demuxer", |
602 "asf", | 762 "asf", |
603 "ASF", | 763 "ASF", |
606 DEMUXER_TYPE_ASF, | 766 DEMUXER_TYPE_ASF, |
607 1, // safe autodetect | 767 1, // safe autodetect |
608 asf_check_header, | 768 asf_check_header, |
609 demux_asf_fill_buffer, | 769 demux_asf_fill_buffer, |
610 demux_open_asf, | 770 demux_open_asf, |
611 NULL, //demux_close_asf, | 771 demux_close_asf, |
612 demux_seek_asf, | 772 demux_seek_asf, |
613 demux_asf_control | 773 demux_asf_control |
614 }; | 774 }; |