int read_asf_header(demuxer_t *demuxer,struct asf_priv* asf){ int hdr_len = asf->header.objh.size - sizeof(asf->header); int hdr_skip = 0; char *hdr = NULL; char guid_buffer[16]; int pos, start = stream_tell(demuxer->stream); uint32_t* streams = NULL; int audio_streams=0; int video_streams=0; uint16_t stream_count=0; 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"); return 0; } if (hdr_len > 1024 * 1024) { mp_msg(MSGT_HEADER, MSGL_ERR, MSGTR_MPDEMUX_ASFHDR_HeaderSizeOver1MB, hdr_len); hdr_skip = hdr_len - 1024 * 1024; hdr_len = 1024 * 1024; } hdr = malloc(hdr_len); if (!hdr) { mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_HeaderMallocFailed, hdr_len); return 0; } stream_read(demuxer->stream, hdr, hdr_len); if (hdr_skip) stream_skip(demuxer->stream, hdr_skip); if (stream_eof(demuxer->stream)) { mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_EOFWhileReadingHeader); goto err_out; } if (is_drm(hdr, hdr_len)) mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_DRMProtected); if ((pos = find_asf_guid(hdr, asf_ext_stream_audio, 0, 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) { sh_audio_t *sh_audio; 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=new_sh_audio(demuxer,streamh->stream_no & 0x7F, NULL); sh_audio->needs_parsing = 1; mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_AudioID, "asfheader", 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; if (!get_ext_stream_properties(hdr, hdr_len, streamh->stream_no, asf, 0)) goto len_err_out; } } // find stream headers // 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) { 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); mp_msg(MSGT_HEADER, MSGL_V, "stream type: %s\n", asf_chunk_type(streamh->type)); mp_msg(MSGT_HEADER, MSGL_V, "stream concealment: %s\n", asf_chunk_type(streamh->concealment)); mp_msg(MSGT_HEADER, MSGL_V, "type: %d bytes, stream: %d bytes ID: %d\n", (int)streamh->type_size, (int)streamh->stream_size, (int)streamh->stream_no); mp_msg(MSGT_HEADER, MSGL_V, "unk1: %lX unk2: %X\n", (unsigned long)streamh->unk1, (unsigned int)streamh->unk2); mp_msg(MSGT_HEADER, MSGL_V, "FILEPOS=0x%X\n", pos + start); // type-specific data: buffer = &hdr[pos]; pos += streamh->type_size; if (pos > hdr_len) goto len_err_out; switch(ASF_LOAD_GUID_PREFIX(streamh->type)){ case ASF_GUID_PREFIX_audio_stream: { sh_audio_t* sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F, NULL); mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_AudioID, "asfheader", streamh->stream_no & 0x7F); ++audio_streams; 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; } case ASF_GUID_PREFIX_video_stream: { unsigned int len; float asp_ratio; sh_video_t* sh_video=new_sh_video(demuxer,streamh->stream_no & 0x7F); mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_VideoID, "asfheader", streamh->stream_no & 0x7F); len=streamh->type_size-(4+4+1+2); ++video_streams; // sh_video->bih=malloc(chunksize); memset(sh_video->bih,0,chunksize); sh_video->bih=calloc((len<sizeof(*sh_video->bih))?sizeof(*sh_video->bih):len,1); memcpy(sh_video->bih,&buffer[4+4+1+2],len); le2me_BITMAPINFOHEADER(sh_video->bih); if (sh_video->bih->biSize > len && sh_video->bih->biSize > sizeof(*sh_video->bih)) sh_video->bih->biSize = len; 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; asf->dvr_last_vid_pts=0.0; } else asf->asf_is_dvr_ms=0; if (!get_ext_stream_properties(hdr, hdr_len, streamh->stream_no, asf, 1)) goto len_err_out; if (get_meta(hdr, hdr_len, streamh->stream_no, &asp_ratio)) { sh_video->aspect = asp_ratio * sh_video->bih->biWidth / sh_video->bih->biHeight; } sh_video->i_bps = asf->bps; 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; break; } } // stream-specific data: // stream_read(demuxer->stream,(char*) buffer,streamh.stream_size); } // find file header pos = find_asf_guid(hdr, asf_file_header_guid, 0, hdr_len); if (pos >= 0) { ASF_file_header_t *fileh = (ASF_file_header_t *)&hdr[pos]; pos += sizeof(ASF_file_header_t); if (pos > hdr_len) goto len_err_out; le2me_ASF_file_header_t(fileh); mp_msg(MSGT_HEADER, MSGL_V, "ASF: packets: %d flags: %d " "max_packet_size: %d min_packet_size: %d max_bitrate: %d " "preroll: %d\n", (int)fileh->num_packets, (int)fileh->flags, (int)fileh->min_packet_size, (int)fileh->max_packet_size, (int)fileh->max_bitrate, (int)fileh->preroll); asf->packetsize=fileh->max_packet_size; asf->packet=malloc(asf->packetsize); // !!! asf->packetrate=fileh->max_bitrate/8.0/(double)asf->packetsize; asf->movielength=(fileh->play_duration-10000*fileh->preroll)/10000000.0; } // find content header pos = find_asf_guid(hdr, asf_content_desc_guid, 0, hdr_len); if (pos >= 0) { ASF_content_description_t *contenth = (ASF_content_description_t *)&hdr[pos]; char *string=NULL; uint16_t* wstring = NULL; uint16_t len; pos += sizeof(ASF_content_description_t); if (pos > hdr_len) goto len_err_out; le2me_ASF_content_description_t(contenth); mp_msg(MSGT_HEADER,MSGL_V,"\n"); // extract the title if((len = contenth->title_size) != 0) { wstring = (uint16_t*)&hdr[pos]; pos += len; if (pos > hdr_len) goto len_err_out; if ((string = get_ucs2str(wstring, len))) { mp_msg(MSGT_HEADER,MSGL_V," Title: %s\n", string); demux_info_add(demuxer, "title", string); free(string); } } // extract the author if((len = contenth->author_size) != 0) { wstring = (uint16_t*)&hdr[pos]; pos += len; if (pos > hdr_len) goto len_err_out; if ((string = get_ucs2str(wstring, len))) { mp_msg(MSGT_HEADER,MSGL_V," Author: %s\n", string); demux_info_add(demuxer, "author", string); free(string); } } // extract the copyright if((len = contenth->copyright_size) != 0) { wstring = (uint16_t*)&hdr[pos]; pos += len; if (pos > hdr_len) goto len_err_out; if ((string = get_ucs2str(wstring, len))) { mp_msg(MSGT_HEADER,MSGL_V," Copyright: %s\n", string); demux_info_add(demuxer, "copyright", string); free(string); } } // extract the comment if((len = contenth->comment_size) != 0) { wstring = (uint16_t*)&hdr[pos]; pos += len; if (pos > hdr_len) goto len_err_out; if ((string = get_ucs2str(wstring, len))) { mp_msg(MSGT_HEADER,MSGL_V," Comment: %s\n", string); demux_info_add(demuxer, "comments", string); free(string); } } // extract the rating if((len = contenth->rating_size) != 0) { wstring = (uint16_t*)&hdr[pos]; pos += len; if (pos > hdr_len) goto len_err_out; if ((string = get_ucs2str(wstring, len))) { mp_msg(MSGT_HEADER,MSGL_V," Rating: %s\n", string); free(string); } } mp_msg(MSGT_HEADER,MSGL_V,"\n"); } // find content header pos = find_asf_guid(hdr, asf_stream_group_guid, 0, hdr_len); if (pos >= 0) { int max_streams = (hdr_len - pos - 2) / 6; uint16_t stream_id, i; uint32_t max_bitrate; char *ptr = &hdr[pos]; mp_msg(MSGT_HEADER,MSGL_V,"============ ASF Stream group == START ===\n"); if(max_streams <= 0) goto len_err_out; stream_count = AV_RL16(ptr); ptr += sizeof(uint16_t); if(stream_count > max_streams) stream_count = max_streams; if(stream_count > 0) streams = malloc(2*stream_count*sizeof(uint32_t)); mp_msg(MSGT_HEADER,MSGL_V," stream count=[0x%x][%u]\n", stream_count, stream_count ); for( i=0 ; i<stream_count ; i++ ) { stream_id = AV_RL16(ptr); ptr += sizeof(uint16_t); max_bitrate = AV_RL32(ptr); ptr += sizeof(uint32_t); mp_msg(MSGT_HEADER,MSGL_V," stream id=[0x%x][%u]\n", stream_id, stream_id ); mp_msg(MSGT_HEADER,MSGL_V," max bitrate=[0x%x][%u]\n", max_bitrate, max_bitrate ); streams[2*i] = stream_id; streams[2*i+1] = max_bitrate; } mp_msg(MSGT_HEADER,MSGL_V,"============ ASF Stream group == END ===\n"); } free(hdr); hdr = NULL; start = stream_tell(demuxer->stream); // start of first data chunk stream_read(demuxer->stream, guid_buffer, 16); if (memcmp(guid_buffer, asf_data_chunk_guid, 16) != 0) { mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_NoDataChunkAfterHeader); free(streams); streams = NULL; return 0; } // read length of chunk data_len = stream_read_qword_le(demuxer->stream); demuxer->movi_start = stream_tell(demuxer->stream) + 26; demuxer->movi_end = start + data_len; mp_msg(MSGT_HEADER, MSGL_V, "Found movie at 0x%X - 0x%X\n", (int)demuxer->movi_start, (int)demuxer->movi_end); if(streams) { // stream selection is done in the network code, it shouldn't be done here // as the servers often do not care about what we requested. #if 0 uint32_t vr = 0, ar = 0,i; #ifdef CONFIG_NETWORKING if( demuxer->stream->streaming_ctrl!=NULL ) { if( demuxer->stream->streaming_ctrl->bandwidth!=0 && demuxer->stream->streaming_ctrl->data!=NULL ) { best_audio = ((asf_http_streaming_ctrl_t*)demuxer->stream->streaming_ctrl->data)->audio_id; best_video = ((asf_http_streaming_ctrl_t*)demuxer->stream->streaming_ctrl->data)->video_id; } } else #endif for(i = 0; i < stream_count; i++) { uint32_t id = streams[2*i]; uint32_t rate = streams[2*i+1]; if(demuxer->v_streams[id] && rate > vr) { vr = rate; best_video = id; } else if(demuxer->a_streams[id] && rate > ar) { ar = rate; best_audio = id; } } #endif free(streams); streams = NULL; } mp_msg(MSGT_HEADER,MSGL_V,"ASF: %d audio and %d video streams found\n",audio_streams,video_streams); if(!audio_streams) demuxer->audio->id=-2; // nosound else if(best_audio > 0 && demuxer->audio->id == -1) demuxer->audio->id=best_audio; if(!video_streams){ if(!audio_streams){ mp_msg(MSGT_HEADER,MSGL_ERR,MSGTR_MPDEMUX_ASFHDR_AudioVideoHeaderNotFound); return 0; } demuxer->video->id=-2; // audio-only } else if (best_video > 0 && demuxer->video->id == -1) demuxer->video->id = best_video; #if 0 if( mp_msg_test(MSGT_HEADER,MSGL_V) ){ printf("ASF duration: %d\n",(int)fileh.duration); printf("ASF start pts: %d\n",(int)fileh.start_timestamp); printf("ASF end pts: %d\n",(int)fileh.end_timestamp); } #endif return 1; len_err_out: mp_msg(MSGT_HEADER, MSGL_FATAL, MSGTR_MPDEMUX_ASFHDR_InvalidLengthInASFHeader); err_out: if (hdr) free(hdr); if (streams) free(streams); return 0; }
static void avifile_write_header(muxer_t *muxer){ uint32_t riff[3]; unsigned int dmlh[1]; unsigned int i; unsigned int hdrsize; muxer_info_t info[16]; VideoPropHeader vprp; uint32_t aspect = avi_aspect(muxer->def_v); struct avi_stream_info *vsi = muxer->def_v->priv; int isodml = vsi->riffofspos > 0; mp_msg(MSGT_MUXER, MSGL_INFO, MSGTR_WritingHeader); if (aspect == 0) { mp_msg(MSGT_MUXER, MSGL_INFO, "ODML: Aspect information not (yet?) available or unspecified, not writing vprp header.\n"); } else { mp_msg(MSGT_MUXER, MSGL_INFO, "ODML: vprp aspect is %d:%d.\n", aspect >> 16, aspect & 0xffff); } /* deal with stream delays */ for (i = 0; muxer->streams[i] && i < MUXER_MAX_STREAMS; ++i) { muxer_stream_t *s = muxer->streams[i]; if (s->type == MUXER_TYPE_AUDIO && muxer->audio_delay_fix > 0.0) { s->h.dwStart = muxer->audio_delay_fix * s->h.dwRate/s->h.dwScale + 0.5; mp_msg(MSGT_MUXER, MSGL_INFO, MSGTR_SettingAudioDelay, (float)s->h.dwStart * s->h.dwScale/s->h.dwRate); } if (s->type == MUXER_TYPE_VIDEO && muxer->audio_delay_fix < 0.0) { s->h.dwStart = -muxer->audio_delay_fix * s->h.dwRate/s->h.dwScale + 0.5; mp_msg(MSGT_MUXER, MSGL_INFO, MSGTR_SettingVideoDelay, (float)s->h.dwStart * s->h.dwScale/s->h.dwRate); } } if (isodml) { unsigned int rifflen, movilen; int i; vsi->riffofs[vsi->riffofspos+1] = muxer->file_end; /* fixup RIFF lengths */ for (i=0; i<=vsi->riffofspos; i++) { rifflen = vsi->riffofs[i+1] - vsi->riffofs[i] - 8; movilen = le2me_32(rifflen - 12); rifflen = le2me_32(rifflen); stream_seek(muxer->stream, vsi->riffofs[i]+4); stream_write_buffer(muxer->stream,&rifflen,4); /* fixup movi length */ if (i > 0) { stream_seek(muxer->stream, vsi->riffofs[i]+16); stream_write_buffer(muxer->stream,&movilen,4); } } stream_seek(muxer->stream, 12); } else { // RIFF header: riff[0]=mmioFOURCC('R','I','F','F'); riff[1]=muxer->file_end-2*sizeof(unsigned int); // filesize riff[2]=formtypeAVI; // 'AVI ' riff[0]=le2me_32(riff[0]); riff[1]=le2me_32(riff[1]); riff[2]=le2me_32(riff[2]); stream_write_buffer(muxer->stream,&riff,12); } // update AVI header: if(muxer->def_v){ int i; muxer->avih.dwMicroSecPerFrame=1000000.0*muxer->def_v->h.dwScale/muxer->def_v->h.dwRate; // muxer->avih.dwMaxBytesPerSec=1000000; // dummy!!!!! FIXME // muxer->avih.dwPaddingGranularity=2; // ??? muxer->avih.dwFlags|=AVIF_ISINTERLEAVED|AVIF_TRUSTCKTYPE; muxer->avih.dwTotalFrames=0; for (i=0; i<muxer->idx_pos; i++) { if (muxer->idx[i].ckid == muxer->def_v->ckid) muxer->avih.dwTotalFrames++; } // muxer->avih.dwSuggestedBufferSize=muxer->def_v->h.dwSuggestedBufferSize; muxer->avih.dwWidth=muxer->def_v->bih->biWidth; muxer->avih.dwHeight=muxer->def_v->bih->biHeight; } // AVI header: hdrsize=sizeof(muxer->avih)+8; if (isodml) hdrsize+=sizeof(dmlh)+20; // dmlh // calc total header size: for(i=0;i<muxer->avih.dwStreams;i++){ muxer_stream_t *s = muxer->streams[i]; struct avi_stream_info *si = s->priv; hdrsize+=12; // LIST hdrsize+=sizeof(muxer->streams[i]->h)+8; // strh switch(muxer->streams[i]->type){ case MUXER_TYPE_VIDEO: hdrsize+=muxer->streams[i]->bih->biSize+8; // strf if (aspect != 0) { hdrsize+=8+4*(9+8*1); // vprp } break; case MUXER_TYPE_AUDIO: hdrsize+=WFSIZE(muxer->streams[i]->wf)+8; // strf break; } if (isodml && si && si->superidx && si->superidxsize) { hdrsize += 32 + 16*si->superidxsize; //indx } } write_avi_list(muxer->stream,listtypeAVIHEADER,hdrsize); le2me_MainAVIHeader(&muxer->avih); write_avi_chunk(muxer->stream,ckidAVIMAINHDR,sizeof(muxer->avih),&muxer->avih); /* MainAVIHeader */ le2me_MainAVIHeader(&muxer->avih); // stream headers: for(i=0;i<muxer->avih.dwStreams;i++){ muxer_stream_t *s = muxer->streams[i]; struct avi_stream_info *si = s->priv; unsigned int idxhdr[8]; int j,n; hdrsize=sizeof(s->h)+8; // strh if (si && si->superidx && si->superidxsize) { hdrsize += 32 + 16*si->superidxsize; //indx } switch(s->type){ case MUXER_TYPE_VIDEO: hdrsize+=s->bih->biSize+8; // strf s->h.fccHandler = s->bih->biCompression; s->h.rcFrame.right = s->bih->biWidth; s->h.rcFrame.bottom = s->bih->biHeight; if (aspect != 0) { // fill out vprp info memset(&vprp, 0, sizeof(vprp)); vprp.dwVerticalRefreshRate = (s->h.dwRate+s->h.dwScale-1)/s->h.dwScale; vprp.dwHTotalInT = muxer->avih.dwWidth; vprp.dwVTotalInLines = muxer->avih.dwHeight; vprp.dwFrameAspectRatio = aspect; vprp.dwFrameWidthInPixels = muxer->avih.dwWidth; vprp.dwFrameHeightInLines = muxer->avih.dwHeight; vprp.nbFieldPerFrame = 1; vprp.FieldInfo[0].CompressedBMHeight = muxer->avih.dwHeight; vprp.FieldInfo[0].CompressedBMWidth = muxer->avih.dwWidth; vprp.FieldInfo[0].ValidBMHeight = muxer->avih.dwHeight; vprp.FieldInfo[0].ValidBMWidth = muxer->avih.dwWidth; hdrsize+=8+4*(9+8*1); // vprp } break; case MUXER_TYPE_AUDIO: hdrsize+=WFSIZE(s->wf)+8; // strf s->h.fccHandler = s->wf->wFormatTag; break; } write_avi_list(muxer->stream,listtypeSTREAMHEADER,hdrsize); le2me_AVIStreamHeader(&s->h); write_avi_chunk(muxer->stream,ckidSTREAMHEADER,sizeof(s->h),&s->h); /* AVISTreamHeader */ // strh le2me_AVIStreamHeader(&s->h); switch(s->type){ case MUXER_TYPE_VIDEO: { int biSize=s->bih->biSize; le2me_BITMAPINFOHEADER(s->bih); write_avi_chunk(muxer->stream,ckidSTREAMFORMAT,biSize,s->bih); /* BITMAPINFOHEADER */ le2me_BITMAPINFOHEADER(s->bih); if (aspect != 0) { int fields = vprp.nbFieldPerFrame; le2me_VideoPropHeader(&vprp); le2me_VIDEO_FIELD_DESC(&vprp.FieldInfo[0]); le2me_VIDEO_FIELD_DESC(&vprp.FieldInfo[1]); write_avi_chunk(muxer->stream,mmioFOURCC('v','p','r','p'), sizeof(VideoPropHeader) - sizeof(VIDEO_FIELD_DESC)*(2-fields), &vprp); /* Video Properties Header */ } } break; case MUXER_TYPE_AUDIO: { int wfsize = WFSIZE(s->wf); le2me_WAVEFORMATEX(s->wf); write_avi_chunk(muxer->stream,ckidSTREAMFORMAT,wfsize,s->wf); /* WAVEFORMATEX */ le2me_WAVEFORMATEX(s->wf); } break; } if (isodml && si && si->superidx && si->superidxsize) { n = si->superidxsize; idxhdr[0] = le2me_32(mmioFOURCC('i', 'n', 'd', 'x')); idxhdr[1] = le2me_32(24 + 16*n); idxhdr[2] = le2me_32(0x00000004); idxhdr[3] = le2me_32(si->superidxpos); idxhdr[4] = le2me_32(s->ckid); idxhdr[5] = 0; idxhdr[6] = 0; idxhdr[7] = 0; stream_write_buffer(muxer->stream,idxhdr,sizeof(idxhdr)); for (j=0; j<n; j++) { struct avi_odmlsuperidx_entry *entry = &si->superidx[j]; unsigned int data[4]; data[0] = le2me_32(entry->ofs); data[1] = le2me_32(entry->ofs >> 32); data[2] = le2me_32(entry->len); data[3] = le2me_32(entry->duration); stream_write_buffer(muxer->stream,data,sizeof(data)); } } }
void read_avi_header(demuxer_t *demuxer,int index_mode){ sh_audio_t *sh_audio=NULL; sh_video_t *sh_video=NULL; int stream_id=-1; int idxfix_videostream=0; int idxfix_divx=0; avi_priv_t* priv=demuxer->priv; off_t list_end=0; //---- AVI header: priv->idx_size=0; priv->audio_streams=0; while(1){ int id=stream_read_dword_le(demuxer->stream); unsigned chunksize,size2; static int last_fccType=0; static int last_fccHandler=0; char* hdr=NULL; // if(stream_eof(demuxer->stream)) break; // Imply -forceidx if -saveidx is specified if (index_file_save) index_mode = 2; // if(id==mmioFOURCC('L','I','S','T')){ unsigned len=stream_read_dword_le(demuxer->stream); // list size id=stream_read_dword_le(demuxer->stream); // list type mp_msg(MSGT_HEADER,MSGL_DBG2,"LIST %.4s len=%u\n",(char *) &id,len); if(len >= 4) { len -= 4; list_end=stream_tell(demuxer->stream)+((len+1)&(~1)); } else { mp_msg(MSGT_HEADER,MSGL_WARN,MSGTR_MPDEMUX_AVIHDR_EmptyList); list_end = 0; } mp_msg(MSGT_HEADER,MSGL_V,"list_end=0x%X\n",(int)list_end); if(id==listtypeAVIMOVIE){ // found MOVI header if(!demuxer->movi_start) demuxer->movi_start=stream_tell(demuxer->stream); demuxer->movi_end=stream_tell(demuxer->stream)+len; mp_msg(MSGT_HEADER,MSGL_V,MSGTR_MPDEMUX_AVIHDR_FoundMovieAt,(int)demuxer->movi_start,(int)demuxer->movi_end); if(demuxer->stream->end_pos>demuxer->movi_end) demuxer->movi_end=demuxer->stream->end_pos; if(index_mode==-2 || index_mode==2 || index_mode==0) break; // reading from non-seekable source (stdin) or forced index or no index forced if(list_end>0) stream_seek(demuxer->stream,list_end); // skip movi list_end=0; } continue; } size2=stream_read_dword_le(demuxer->stream); mp_msg(MSGT_HEADER,MSGL_DBG2,"CHUNK %.4s len=%u\n",(char *) &id,size2); chunksize=(size2+1)&(~1); switch(id){ // Indicates where the subject of the file is archived case mmioFOURCC('I','A','R','L'): hdr="Archival Location";break; // Lists the artist of the original subject of the file; // for example, "Michaelangelo." case mmioFOURCC('I','A','R','T'): hdr="Artist";break; // Lists the name of the person or organization that commissioned // the subject of the file; for example "Pope Julian II." case mmioFOURCC('I','C','M','S'): hdr="Commissioned";break; // Provides general comments about the file or the subject // of the file. If the comment is several sentences long, end each // sentence with a period. Do not include new-line characters. case mmioFOURCC('I','C','M','T'): hdr="Comments";break; // Records the copyright information for the file; for example, // "Copyright Encyclopedia International 1991." If there are multiple // copyrights, separate them by semicolon followed by a space. case mmioFOURCC('I','C','O','P'): hdr="Copyright";break; // Describes whether an image has been cropped and, if so, how it // was cropped; for example, "lower-right corner." case mmioFOURCC('I','C','R','D'): hdr="Creation Date";break; // Describes whether an image has been cropped and, if so, how it // was cropped; for example, "lower-right corner." case mmioFOURCC('I','C','R','P'): hdr="Cropped";break; // Specifies the size of the original subject of the file; for // example, "8.5 in h, 11 in w." case mmioFOURCC('I','D','I','M'): hdr="Dimensions";break; // Stores dots per inch setting of the digitizer used to // produce the file, such as "300." case mmioFOURCC('I','D','P','I'): hdr="Dots Per Inch";break; // Stores the of the engineer who worked on the file. If there are // multiple engineers, separate the names by a semicolon and a blank; // for example, "Smith, John; Adams, Joe." case mmioFOURCC('I','E','N','G'): hdr="Engineer";break; // Describes the original work, such as "landscape,", "portrait," // "still liefe," etc. case mmioFOURCC('I','G','N','R'): hdr="Genre";break; // Provides a list of keywords that refer to the file or subject of the // file. Separate multiple keywords with a semicolon and a blank; // for example, "Seattle, aerial view; scenery." case mmioFOURCC('I','K','E','Y'): hdr="Keywords";break; // ILGT - Describes the changes in the lightness settings on the digitizer // required to produce the file. Note that the format of this information // depends on the hardware used. case mmioFOURCC('I','L','G','T'): hdr="Lightness";break; // IMED - Decribes the original subject of the file, such as // "computer image," "drawing," "lithograph," and so on. case mmioFOURCC('I','M','E','D'): hdr="Medium";break; // INAM - Stores the title of the subject of the file, such as // "Seattle from Above." case mmioFOURCC('I','N','A','M'): hdr="Title";break; // IPLT - Specifies the number of colors requested when digitizing // an image, such as "256." case mmioFOURCC('I','P','L','T'): hdr="Palette Setting";break; // IPRD - Specifies the name of title the file was originally intended // for, such as "Encyclopedia of Pacific Northwest Geography." case mmioFOURCC('I','P','R','D'): hdr="Product";break; // ISBJ - Decsribes the contents of the file, such as // "Aerial view of Seattle." case mmioFOURCC('I','S','B','J'): hdr="Subject";break; // ISFT - Identifies the name of the software packages used to create the // file, such as "Microsoft WaveEdit" case mmioFOURCC('I','S','F','T'): hdr="Software";break; // ISHP - Identifies the change in sharpness for the digitizer // required to produce the file (the format depends on the hardware used). case mmioFOURCC('I','S','H','P'): hdr="Sharpness";break; // ISRC - Identifies the name of the person or organization who // suplied the original subject of the file; for example, "Try Research." case mmioFOURCC('I','S','R','C'): hdr="Source";break; // ISRF - Identifies the original form of the material that was digitized, // such as "slide," "paper," "map," and so on. This is not necessarily // the same as IMED case mmioFOURCC('I','S','R','F'): hdr="Source Form";break; // ITCH - Identifies the technician who digitized the subject file; // for example, "Smith, John." case mmioFOURCC('I','T','C','H'): hdr="Technician";break; case mmioFOURCC('I','S','M','P'): hdr="Time Code";break; case mmioFOURCC('I','D','I','T'): hdr="Digitization Time";break; case ckidAVIMAINHDR: // read 'avih' stream_read(demuxer->stream,(char*) &avih,FFMIN(size2,sizeof(avih))); le2me_MainAVIHeader(&avih); // swap to machine endian chunksize-=FFMIN(size2,sizeof(avih)); if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_avih(&avih,MSGL_V); // else print_avih_flags(&avih,MSGL_V); break; case ckidSTREAMHEADER: { // read 'strh' AVIStreamHeader h; stream_read(demuxer->stream,(char*) &h,FFMIN(size2,sizeof(h))); le2me_AVIStreamHeader(&h); // swap to machine endian chunksize-=FFMIN(size2,sizeof(h)); ++stream_id; if(h.fccType==streamtypeVIDEO){ sh_video=new_sh_video(demuxer,stream_id); mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_VideoID, "aviheader", stream_id); memcpy(&sh_video->video,&h,sizeof(h)); sh_video->stream_delay = (float)sh_video->video.dwStart * sh_video->video.dwScale/sh_video->video.dwRate; } else if(h.fccType==streamtypeAUDIO){ sh_audio=new_sh_audio(demuxer,stream_id); mp_msg(MSGT_DEMUX, MSGL_INFO, MSGTR_AudioID, "aviheader", stream_id); memcpy(&sh_audio->audio,&h,sizeof(h)); sh_audio->stream_delay = (float)sh_audio->audio.dwStart * sh_audio->audio.dwScale/sh_audio->audio.dwRate; } last_fccType=h.fccType; last_fccHandler=h.fccHandler; if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_strh(&h,MSGL_V); break; } case mmioFOURCC('i', 'n', 'd', 'x'): { uint32_t i; avisuperindex_chunk *s; if(!index_mode) break; if(chunksize<=24){ break; } priv->suidx_size++; priv->suidx = realloc_struct(priv->suidx, priv->suidx_size, sizeof (avisuperindex_chunk)); s = &priv->suidx[priv->suidx_size-1]; chunksize-=24; memcpy(s->fcc, "indx", 4); s->dwSize = size2; s->wLongsPerEntry = stream_read_word_le(demuxer->stream); s->bIndexSubType = stream_read_char(demuxer->stream); s->bIndexType = stream_read_char(demuxer->stream); s->nEntriesInUse = stream_read_dword_le(demuxer->stream); *(uint32_t *)s->dwChunkId = stream_read_dword_le(demuxer->stream); stream_read(demuxer->stream, (char *)s->dwReserved, 3*4); memset(s->dwReserved, 0, 3*4); print_avisuperindex_chunk(s,MSGL_V); // Check and fix this useless crap if(s->wLongsPerEntry != sizeof (avisuperindex_entry)/4) { mp_msg (MSGT_HEADER, MSGL_WARN, "Broken super index chunk size: %u\n",s->wLongsPerEntry); s->wLongsPerEntry = sizeof(avisuperindex_entry)/4; } if( ((chunksize/4)/s->wLongsPerEntry) < s->nEntriesInUse){ mp_msg (MSGT_HEADER, MSGL_WARN, "Broken super index chunk\n"); s->nEntriesInUse = (chunksize/4)/s->wLongsPerEntry; } s->aIndex = calloc(s->nEntriesInUse, sizeof (avisuperindex_entry)); s->stdidx = calloc(s->nEntriesInUse, sizeof (avistdindex_chunk)); // now the real index of indices for (i=0; i<s->nEntriesInUse; i++) { chunksize-=16; s->aIndex[i].qwOffset = stream_read_qword_le(demuxer->stream); s->aIndex[i].dwSize = stream_read_dword_le(demuxer->stream); s->aIndex[i].dwDuration = stream_read_dword_le(demuxer->stream); mp_msg (MSGT_HEADER, MSGL_V, "ODML (%.4s): [%d] 0x%016"PRIx64" 0x%04x %u\n", (s->dwChunkId), i, (uint64_t)s->aIndex[i].qwOffset, s->aIndex[i].dwSize, s->aIndex[i].dwDuration); } break; } case ckidSTREAMFORMAT: { // read 'strf' if(last_fccType==streamtypeVIDEO){ sh_video->bih=calloc(FFMAX(chunksize, sizeof(BITMAPINFOHEADER)), 1); // sh_video->bih=malloc(chunksize); memset(sh_video->bih,0,chunksize); mp_msg(MSGT_HEADER,MSGL_V,MSGTR_MPDEMUX_AVIHDR_FoundBitmapInfoHeader,chunksize,sizeof(BITMAPINFOHEADER)); stream_read(demuxer->stream,(char*) sh_video->bih,chunksize); le2me_BITMAPINFOHEADER(sh_video->bih); // swap to machine endian if (sh_video->bih->biSize > chunksize && sh_video->bih->biSize > sizeof(BITMAPINFOHEADER)) sh_video->bih->biSize = chunksize; // fixup MS-RLE header (seems to be broken for <256 color files) if(sh_video->bih->biCompression<=1 && sh_video->bih->biSize==40) sh_video->bih->biSize=chunksize; if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(sh_video->bih,MSGL_V); chunksize=0; 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; sh_video->format = sh_video->bih->biCompression; // if(demuxer->video->id==-1) demuxer->video->id=stream_id; // IdxFix: idxfix_videostream=stream_id; switch(sh_video->bih->biCompression){ case mmioFOURCC('M', 'P', 'G', '4'): case mmioFOURCC('m', 'p', 'g', '4'): case mmioFOURCC('D', 'I', 'V', '1'): idxfix_divx=3; // set index recovery mpeg4 flavour: msmpeg4v1 mp_msg(MSGT_HEADER,MSGL_V,MSGTR_MPDEMUX_AVIHDR_RegeneratingKeyfTableForMPG4V1); break; case mmioFOURCC('D', 'I', 'V', '3'): case mmioFOURCC('d', 'i', 'v', '3'): case mmioFOURCC('D', 'I', 'V', '4'): case mmioFOURCC('d', 'i', 'v', '4'): case mmioFOURCC('D', 'I', 'V', '5'): case mmioFOURCC('d', 'i', 'v', '5'): case mmioFOURCC('D', 'I', 'V', '6'): case mmioFOURCC('d', 'i', 'v', '6'): case mmioFOURCC('M', 'P', '4', '3'): case mmioFOURCC('m', 'p', '4', '3'): case mmioFOURCC('M', 'P', '4', '2'): case mmioFOURCC('m', 'p', '4', '2'): case mmioFOURCC('D', 'I', 'V', '2'): case mmioFOURCC('A', 'P', '4', '1'): idxfix_divx=1; // set index recovery mpeg4 flavour: msmpeg4v3 mp_msg(MSGT_HEADER,MSGL_V,MSGTR_MPDEMUX_AVIHDR_RegeneratingKeyfTableForDIVX3); break; case mmioFOURCC('D', 'I', 'V', 'X'): case mmioFOURCC('d', 'i', 'v', 'x'): case mmioFOURCC('D', 'X', '5', '0'): case mmioFOURCC('X', 'V', 'I', 'D'): case mmioFOURCC('x', 'v', 'i', 'd'): case mmioFOURCC('F', 'M', 'P', '4'): case mmioFOURCC('f', 'm', 'p', '4'): idxfix_divx=2; // set index recovery mpeg4 flavour: generic mpeg4 mp_msg(MSGT_HEADER,MSGL_V,MSGTR_MPDEMUX_AVIHDR_RegeneratingKeyfTableForMPEG4); break; } } else if(last_fccType==streamtypeAUDIO){ unsigned wf_size = chunksize<sizeof(WAVEFORMATEX)?sizeof(WAVEFORMATEX):chunksize; sh_audio->wf=calloc(wf_size,1); // sh_audio->wf=malloc(chunksize); memset(sh_audio->wf,0,chunksize); mp_msg(MSGT_HEADER,MSGL_V,MSGTR_MPDEMUX_AVIHDR_FoundWaveFmt,chunksize,sizeof(WAVEFORMATEX)); stream_read(demuxer->stream,(char*) sh_audio->wf,chunksize); le2me_WAVEFORMATEX(sh_audio->wf); if (sh_audio->wf->cbSize != 0 && wf_size < sizeof(WAVEFORMATEX)+sh_audio->wf->cbSize) { sh_audio->wf=realloc(sh_audio->wf, sizeof(WAVEFORMATEX)+sh_audio->wf->cbSize); } sh_audio->format=sh_audio->wf->wFormatTag; if (sh_audio->format == 1 && last_fccHandler == mmioFOURCC('A', 'x', 'a', 'n')) sh_audio->format = last_fccHandler; sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec; chunksize=0; if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_audio->wf,MSGL_V); ++priv->audio_streams; // if(demuxer->audio->id==-1) demuxer->audio->id=stream_id; } break; } case mmioFOURCC('v', 'p', 'r', 'p'): { VideoPropHeader *vprp = malloc(chunksize); unsigned int i; stream_read(demuxer->stream, (void*)vprp, chunksize); le2me_VideoPropHeader(vprp); chunksize -= sizeof(*vprp)-sizeof(vprp->FieldInfo); chunksize /= sizeof(VIDEO_FIELD_DESC); if (vprp->nbFieldPerFrame > chunksize) { vprp->nbFieldPerFrame = chunksize; } chunksize = 0; for (i=0; i<vprp->nbFieldPerFrame; i++) { le2me_VIDEO_FIELD_DESC(&vprp->FieldInfo[i]); } if (sh_video) { sh_video->aspect = GET_AVI_ASPECT(vprp->dwFrameAspectRatio); } if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_vprp(vprp,MSGL_V); free(vprp); break; } case mmioFOURCC('d', 'm', 'l', 'h'): { // dmlh 00 00 00 04 frms unsigned int total_frames = stream_read_dword_le(demuxer->stream); mp_msg(MSGT_HEADER,MSGL_V,MSGTR_MPDEMUX_AVIHDR_FoundAVIV2Header, chunksize, total_frames); stream_skip(demuxer->stream, chunksize-4); chunksize = 0; } break; case ckidAVINEWINDEX: if(demuxer->movi_end>stream_tell(demuxer->stream)) demuxer->movi_end=stream_tell(demuxer->stream); // fixup movi-end if(index_mode && !priv->isodml){ int i; priv->idx_size=size2>>4; mp_msg(MSGT_HEADER,MSGL_V,MSGTR_MPDEMUX_AVIHDR_ReadingIndexBlockChunksForFrames, priv->idx_size,avih.dwTotalFrames, (int64_t)stream_tell(demuxer->stream)); priv->idx=malloc(priv->idx_size<<4); // printf("\nindex to %p !!!!! (priv=%p)\n",priv->idx,priv); stream_read(demuxer->stream,(char*)priv->idx,priv->idx_size<<4); for (i = 0; i < priv->idx_size; i++) { // swap index to machine endian AVIINDEXENTRY *entry=(AVIINDEXENTRY*)priv->idx + i; le2me_AVIINDEXENTRY(entry); /* * We (ab)use the upper word for bits 32-47 of the offset, so * we'll clear them here. * FIXME: AFAIK no codec uses them, but if one does it will break */ entry->dwFlags&=0xffff; } chunksize-=priv->idx_size<<4; if( mp_msg_test(MSGT_HEADER,MSGL_DBG2) ) print_index(priv->idx,priv->idx_size,MSGL_DBG2); } break; /* added May 2002 */ case mmioFOURCC('R','I','F','F'): { char riff_type[4]; mp_msg(MSGT_HEADER, MSGL_V, MSGTR_MPDEMUX_AVIHDR_AdditionalRIFFHdr); stream_read(demuxer->stream, riff_type, sizeof riff_type); if (strncmp(riff_type, "AVIX", sizeof riff_type)) mp_msg(MSGT_HEADER, MSGL_WARN, MSGTR_MPDEMUX_AVIHDR_WarnNotExtendedAVIHdr); else { /* * We got an extended AVI header, so we need to switch to * ODML to get seeking to work, provided we got indx chunks * in the header (suidx_size > 0). */ if (priv->suidx_size > 0) priv->isodml = 1; } chunksize = 0; list_end = 0; /* a new list will follow */ break; } case ckidAVIPADDING: stream_skip(demuxer->stream, chunksize); chunksize = 0; break; } if(hdr){ mp_msg(MSGT_HEADER,MSGL_V,"hdr=%s size=%u\n",hdr,size2); if(size2==3) chunksize=1; // empty else { char buf[256]; int len=(size2<250)?size2:250; stream_read(demuxer->stream,buf,len); chunksize-=len; buf[len]=0; mp_msg(MSGT_HEADER,MSGL_V,"%-10s: %s\n",hdr,buf); demux_info_add(demuxer, hdr, buf); } } mp_msg(MSGT_HEADER,MSGL_DBG2,"list_end=0x%"PRIX64" pos=0x%"PRIX64" chunksize=0x%"PRIX64" next=0x%"PRIX64"\n", (int64_t)list_end, (int64_t)stream_tell(demuxer->stream), (int64_t)chunksize, (int64_t)chunksize+(int64_t)stream_tell(demuxer->stream)); if(list_end>0 && chunksize+stream_tell(demuxer->stream) == list_end) list_end=0; if(list_end>0 && chunksize+stream_tell(demuxer->stream)>list_end){ mp_msg(MSGT_HEADER,MSGL_V,MSGTR_MPDEMUX_AVIHDR_BrokenChunk,chunksize,(char *) &id); stream_seek(demuxer->stream,list_end); list_end=0; } else if(chunksize>0) stream_skip(demuxer->stream,chunksize); else if((int)chunksize<0) mp_msg(MSGT_HEADER,MSGL_WARN,"chunksize=%u (id=%.4s)\n",chunksize,(char *) &id); }