diff options
author | pacman <pacman@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2006-06-06 23:34:21 +0000 |
---|---|---|
committer | pacman <pacman@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2006-06-06 23:34:21 +0000 |
commit | 2a8494d031303d94193992e423f4b0010078fa0d (patch) | |
tree | 81b78ba21f8b2c3b3262c5575df8a6895f1a1b0a /libmpdemux | |
parent | 36e4ad3058a1fea814de21193d9773c66e1b594c (diff) |
Patch from John Donaghy: "fix for audio and video in dvr-ms asf files"
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@18610 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpdemux')
-rw-r--r-- | libmpdemux/asf.h | 3 | ||||
-rw-r--r-- | libmpdemux/asfheader.c | 115 | ||||
-rw-r--r-- | libmpdemux/demux_asf.c | 113 |
3 files changed, 198 insertions, 33 deletions
diff --git a/libmpdemux/asf.h b/libmpdemux/asf.h index 19c588556c..01f9b25857 100644 --- a/libmpdemux/asf.h +++ b/libmpdemux/asf.h @@ -222,6 +222,9 @@ struct asf_priv { unsigned packetsize; double packetrate; unsigned movielength; + int asf_is_dvr_ms; + uint32_t asf_frame_state; + int asf_frame_start_found; }; #endif diff --git a/libmpdemux/asfheader.c b/libmpdemux/asfheader.c index 36f05a7c25..2c5691ed28 100644 --- a/libmpdemux/asfheader.c +++ b/libmpdemux/asfheader.c @@ -34,6 +34,8 @@ #define ASF_GUID_PREFIX_file_header 0x8CABDCA1 #define ASF_GUID_PREFIX_content_desc 0x75b22633 #define ASF_GUID_PREFIX_stream_group 0x7bf875ce +#define ASF_GUID_PREFIX_ext_audio_stream 0x31178C9D +#define ASF_GUID_PREFIX_ext_stream_embed_stream_header 0x3AFB65E2 /* const char asf_audio_stream_guid[16] = {0x40, 0x9e, 0x69, 0xf8, @@ -51,6 +53,12 @@ const char asf_stream_group_guid[16] = {0xce, 0x75, 0xf8, 0x7b, 0x8d, 0x46, 0xd1, 0x11, 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2}; const char asf_data_chunk_guid[16] = {0x36, 0x26, 0xb2, 0x75, 0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c}; +const char asf_ext_stream_embed_stream_header[16] = {0xe2, 0x65, 0xfb, 0x3a, + 0xef, 0x47, 0xf2, 0x40, 0xac, 0x2c, 0x70, 0xa9, 0x0d, 0x71, 0xd3, 0x43}; +const char asf_ext_stream_audio[16] = {0x9d, 0x8c, 0x17, 0x31, + 0xe1, 0x03, 0x28, 0x45, 0xb5, 0x82, 0x3d, 0xf9, 0xdb, 0x22, 0xf5, 0x03}; +const char asf_ext_stream_header[16] = {0xCB, 0xA5, 0xE6, 0x14, + 0x72, 0xC6, 0x32, 0x43, 0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A}; // the variable string is modify in this function @@ -77,6 +85,10 @@ static char* asf_chunk_type(unsigned char* guid) { switch(ASF_LOAD_GUID_PREFIX(guid)){ case ASF_GUID_PREFIX_audio_stream: return "guid_audio_stream"; + case ASF_GUID_PREFIX_ext_audio_stream: + return "guid_ext_audio_stream"; + case ASF_GUID_PREFIX_ext_stream_embed_stream_header: + return "guid_ext_stream_embed_stream_header"; case ASF_GUID_PREFIX_video_stream: return "guid_video_stream"; case ASF_GUID_PREFIX_audio_conceal_none: @@ -144,6 +156,42 @@ int find_asf_guid(char *buf, const char *guid, int cur_pos, int buf_len) return -1; } +static int find_backwards_asf_guid(char *buf, const char *guid, int cur_pos) +{ + int i; + for (i=cur_pos-16; i>0; i--) { + if (memcmp(&buf[i], guid, 16) == 0) + return i + 16 + 8; // point after guid + length + } + return -1; +} + +static int asf_init_audio_stream(demuxer_t *demuxer,struct asf_priv* asf, sh_audio_t* sh_audio, ASF_stream_header_t *streamh, int *ppos, uint8_t** buf, char *hdr, unsigned int hdr_len) +{ + uint8_t *buffer = *buf; + int pos = *ppos; + + sh_audio->wf=calloc((streamh->type_size<sizeof(WAVEFORMATEX))?sizeof(WAVEFORMATEX):streamh->type_size,1); + memcpy(sh_audio->wf,buffer,streamh->type_size); + le2me_WAVEFORMATEX(sh_audio->wf); + if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_audio->wf,MSGL_V); + if(ASF_LOAD_GUID_PREFIX(streamh->concealment)==ASF_GUID_PREFIX_audio_conceal_interleave){ + buffer = &hdr[pos]; + pos += streamh->stream_size; + if (pos > hdr_len) return 0; + asf->scrambling_h=buffer[0]; + asf->scrambling_w=(buffer[2]<<8)|buffer[1]; + asf->scrambling_b=(buffer[4]<<8)|buffer[3]; + if(asf->scrambling_b>0){ + asf->scrambling_w/=asf->scrambling_b; + } + } else { + asf->scrambling_b=asf->scrambling_h=asf->scrambling_w=1; + } + mp_msg(MSGT_HEADER,MSGL_V,"ASF: audio scrambling: %d x %d x %d\n",asf->scrambling_h,asf->scrambling_w,asf->scrambling_b); + return 1; +} + int read_asf_header(demuxer_t *demuxer,struct asf_priv* asf){ int hdr_len = asf->header.objh.size - sizeof(asf->header); char *hdr = NULL; @@ -156,6 +204,9 @@ int read_asf_header(demuxer_t *demuxer,struct asf_priv* asf){ int best_video = -1; int best_audio = -1; uint64_t data_len; + ASF_stream_header_t *streamh; + uint8_t *buffer; + int audio_pos=0; if(hdr_len < 0) { mp_msg(MSGT_HEADER, MSGL_FATAL, "Header size is too small.\n"); @@ -179,12 +230,38 @@ int read_asf_header(demuxer_t *demuxer,struct asf_priv* asf){ goto err_out; } + if ((pos = find_asf_guid(hdr, asf_ext_stream_audio, pos, hdr_len)) >= 0) + { + // Special case: found GUID for dvr-ms audio. + // Now skip back to associated stream header. + int sh_pos=0; + + sh_pos = find_backwards_asf_guid(hdr, asf_stream_header_guid, pos); + + if (sh_pos > 0) { + mp_msg(MSGT_HEADER, MSGL_V, "read_asf_header found dvr-ms audio stream header pos=%d\n", sh_pos); + // found audio stream header - following code reads header and + // initializes audio stream. + audio_pos = pos - 16 - 8; + streamh = (ASF_stream_header_t *)&hdr[sh_pos]; + le2me_ASF_stream_header_t(streamh); + audio_pos += 64; //16+16+4+4+4+16+4; + buffer = &hdr[audio_pos]; + sh_audio_t* sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F); + ++audio_streams; + if (!asf_init_audio_stream(demuxer, asf, sh_audio, streamh, &audio_pos, &buffer, hdr, hdr_len)) + goto len_err_out; + } + } // find stream headers - pos = 0; + // only reset pos if we didnt find dvr_ms audio stream + // if we did find it then we want to avoid reading its header twice + if (audio_pos == 0) + pos = 0; + while ((pos = find_asf_guid(hdr, asf_stream_header_guid, pos, hdr_len)) >= 0) { - ASF_stream_header_t *streamh = (ASF_stream_header_t *)&hdr[pos]; - uint8_t *buffer; + streamh = (ASF_stream_header_t *)&hdr[pos]; pos += sizeof(ASF_stream_header_t); if (pos > hdr_len) goto len_err_out; le2me_ASF_stream_header_t(streamh); @@ -206,24 +283,8 @@ int read_asf_header(demuxer_t *demuxer,struct asf_priv* asf){ case ASF_GUID_PREFIX_audio_stream: { sh_audio_t* sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F); ++audio_streams; - sh_audio->wf=calloc((streamh->type_size<sizeof(WAVEFORMATEX))?sizeof(WAVEFORMATEX):streamh->type_size,1); - memcpy(sh_audio->wf,buffer,streamh->type_size); - le2me_WAVEFORMATEX(sh_audio->wf); - if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_audio->wf,MSGL_V); - if(ASF_LOAD_GUID_PREFIX(streamh->concealment)==ASF_GUID_PREFIX_audio_conceal_interleave){ - buffer = &hdr[pos]; - pos += streamh->stream_size; - if (pos > hdr_len) goto len_err_out; - asf->scrambling_h=buffer[0]; - asf->scrambling_w=(buffer[2]<<8)|buffer[1]; - asf->scrambling_b=(buffer[4]<<8)|buffer[3]; - if(asf->scrambling_b>0){ - asf->scrambling_w/=asf->scrambling_b; - } - } else { - asf->scrambling_b=asf->scrambling_h=asf->scrambling_w=1; - } - mp_msg(MSGT_HEADER,MSGL_V,"ASF: audio scrambling: %d x %d x %d\n",asf->scrambling_h,asf->scrambling_w,asf->scrambling_b); + if (!asf_init_audio_stream(demuxer, asf, sh_audio, streamh, &pos, &buffer, hdr, hdr_len)) + goto len_err_out; //if(demuxer->audio->id==-1) demuxer->audio->id=streamh.stream_no & 0x7F; break; } @@ -235,10 +296,14 @@ int read_asf_header(demuxer_t *demuxer,struct asf_priv* asf){ sh_video->bih=calloc((len<sizeof(BITMAPINFOHEADER))?sizeof(BITMAPINFOHEADER):len,1); memcpy(sh_video->bih,&buffer[4+4+1+2],len); le2me_BITMAPINFOHEADER(sh_video->bih); - if (sh_video->bih->biCompression == mmioFOURCC('D', 'V', 'R', ' ')) - mp_msg(MSGT_DEMUXER, MSGL_WARN, MSGTR_MPDEMUX_ASFHDR_DVRWantsLibavformat); - //sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale; - //sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; + if (sh_video->bih->biCompression == mmioFOURCC('D', 'V', 'R', ' ')) { + //mp_msg(MSGT_DEMUXER, MSGL_WARN, MSGTR_MPDEMUX_ASFHDR_DVRWantsLibavformat); + //sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale; + //sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate; + asf->asf_frame_state=-1; + asf->asf_frame_start_found=0; + asf->asf_is_dvr_ms=1; + } else asf->asf_is_dvr_ms=0; if( mp_msg_test(MSGT_DEMUX,MSGL_V) ) print_video_header(sh_video->bih, MSGL_V); //asf_video_id=streamh.stream_no & 0x7F; //if(demuxer->video->id==-1) demuxer->video->id=streamh.stream_no & 0x7F; diff --git a/libmpdemux/demux_asf.c b/libmpdemux/demux_asf.c index c473caae3a..24bdec5982 100644 --- a/libmpdemux/demux_asf.c +++ b/libmpdemux/demux_asf.c @@ -14,6 +14,11 @@ #include "libvo/fastmemcpy.h" +#define ASFMIN(a,b) ((a) > (b) ? (b) : (a)) +#define SLICE_MIN_START_CODE 0x00000101 +#define SLICE_MAX_START_CODE 0x000001af +#define END_NOT_FOUND -100 + /* * Load 16/32-bit values in little endian byte order * from an unaligned address @@ -21,6 +26,10 @@ #ifdef ARCH_X86 #define LOAD_LE32(p) (*(unsigned int*)(p)) #define LOAD_LE16(p) (*(unsigned short*)(p)) +#define LOAD_BE32(p) (((unsigned char*)(p))[3] | \ + ((unsigned char*)(p))[2]<< 8 | \ + ((unsigned char*)(p))[1]<<16 | \ + ((unsigned char*)(p))[0]<<24 ) #else #define LOAD_LE32(p) (((unsigned char*)(p))[0] | \ ((unsigned char*)(p))[1]<< 8 | \ @@ -28,6 +37,7 @@ ((unsigned char*)(p))[3]<<24 ) #define LOAD_LE16(p) (((unsigned char*)(p))[0] | \ ((unsigned char*)(p))[1]<<8) +#define LOAD_BE32(p) (*(unsigned int*)(p)) #endif // defined at asfheader.c: @@ -64,9 +74,86 @@ static void asf_descrambling(unsigned char **src,unsigned len, struct asf_priv* #define FF_INPUT_BUFFER_PADDING_SIZE 8 #endif +static const uint8_t *find_start_code(const uint8_t * restrict p, const uint8_t *end, uint32_t * restrict state){ + int i; + if(p>=end) + return end; + + for(i=0; i<3; i++){ + uint32_t tmp= *state << 8; + *state= tmp + *(p++); + if(tmp == 0x100 || p==end) + return p; + } + + while(p<end){ + if (p[-1] > 1 ) p+= 3; + else if(p[-2] ) p+= 2; + else if(p[-3]|(p[-1]-1)) p++; + else{ + p++; + break; + } + } + + p= ASFMIN(p, end)-4; + *state= LOAD_BE32(p); + + return p+4; +} + +static int mpeg1_find_frame_end(demuxer_t *demux, const uint8_t *buf, int buf_size) +{ + int i; + struct asf_priv* asf = demux->priv; + + i=0; + if(!asf->asf_frame_start_found){ + for(i=0; i<buf_size; i++){ + i= find_start_code(buf+i, buf+buf_size, &asf->asf_frame_state) - buf - 1; + if(asf->asf_frame_state >= SLICE_MIN_START_CODE && asf->asf_frame_state <= SLICE_MAX_START_CODE){ + i++; + asf->asf_frame_start_found=1; + break; + } + } + } + + if(asf->asf_frame_start_found){ + /* EOF considered as end of frame */ + if (buf_size == 0) + return 0; + + for(; i<buf_size; i++){ + i= find_start_code(buf+i, buf+buf_size, &asf->asf_frame_state) - buf - 1; + if((asf->asf_frame_state&0xFFFFFF00) == 0x100){ + //if NOT in range 257 - 431 + if(asf->asf_frame_state < SLICE_MIN_START_CODE || asf->asf_frame_state > SLICE_MAX_START_CODE){ + asf->asf_frame_start_found=0; + asf->asf_frame_state=-1; + return i-3; + } + } + } + } + return END_NOT_FOUND; +} + +static void demux_asf_append_to_packet(demux_packet_t* dp,unsigned char *data,int len,int offs) +{ + if(dp->len!=offs && offs!=-1) mp_msg(MSGT_DEMUX,MSGL_V,"warning! fragment.len=%d BUT next fragment offset=%d \n",dp->len,offs); + dp->buffer=realloc(dp->buffer,dp->len+len+FF_INPUT_BUFFER_PADDING_SIZE); + memcpy(dp->buffer+dp->len,data,len); + memset(dp->buffer+dp->len+len, 0, FF_INPUT_BUFFER_PADDING_SIZE); + mp_dbg(MSGT_DEMUX,MSGL_DBG4,"data appended! %d+%d\n",dp->len,len); + dp->len+=len; +} + 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){ struct asf_priv* asf = demux->priv; demux_stream_t *ds=NULL; + int close_seg=0; + int frame_end_pos=END_NOT_FOUND; mp_dbg(MSGT_DEMUX,MSGL_DBG4,"demux_asf.read_packet: id=%d seq=%d len=%d\n",id,seq,len); @@ -97,7 +184,23 @@ static int demux_asf_read_packet(demuxer_t *demux,unsigned char *data,int len,in if(ds){ if(ds->asf_packet){ - if(ds->asf_seq!=seq){ + demux_packet_t* dp=ds->asf_packet; + + if (ds==demux->video && asf->asf_is_dvr_ms) { + frame_end_pos=mpeg1_find_frame_end(demux, data, len); + + if (frame_end_pos != END_NOT_FOUND) { + dp->pos=demux->filepos; + if (frame_end_pos > 0) { + demux_asf_append_to_packet(dp,data,frame_end_pos,offs); + data += frame_end_pos; + len -= frame_end_pos; + } + close_seg = 1; + } else seq = ds->asf_seq; + } else close_seg = ds->asf_seq!=seq; + + if(close_seg){ // closed segment, finalize packet: if(ds==demux->audio) if(asf->scrambling_h>1 && asf->scrambling_w>1 && asf->scrambling_b>0) @@ -106,13 +209,7 @@ static int demux_asf_read_packet(demuxer_t *demux,unsigned char *data,int len,in ds->asf_packet=NULL; } else { // append data to it! - demux_packet_t* dp=ds->asf_packet; - if(dp->len!=offs && offs!=-1) mp_msg(MSGT_DEMUX,MSGL_V,"warning! fragment.len=%d BUT next fragment offset=%d \n",dp->len,offs); - dp->buffer=realloc(dp->buffer,dp->len+len+FF_INPUT_BUFFER_PADDING_SIZE); - memcpy(dp->buffer+dp->len,data,len); - memset(dp->buffer+dp->len+len, 0, FF_INPUT_BUFFER_PADDING_SIZE); - mp_dbg(MSGT_DEMUX,MSGL_DBG4,"data appended! %d+%d\n",dp->len,len); - dp->len+=len; + demux_asf_append_to_packet(dp,data,len,offs); // we are ready now. return 1; } |