/** \fn ADM_codecIdFindByFourcc \brief get lav codec if from fourcc (used by muxer) */ CodecID ADM_codecIdFindByFourcc(const char *fcc) { uint32_t fid=fourCC::get((uint8_t *)fcc); // Special cases if (isMSMpeg4Compatible (fid) == 1) { return CODEC_ID_MSMPEG4V3; } if (isDVCompatible(fid))//"CDVC")) { return CODEC_ID_DVVIDEO; } if (isH264Compatible (fid)) { return CODEC_ID_H264; } if (isMpeg4Compatible (fid) == 1) { return CODEC_ID_MPEG4; } uint32_t nb=sizeof(ffCodec)/sizeof(ffVideoCodec); for(int i=0;i<nb;i++) { if(!strcmp(fcc,ffCodec[i].string)) return ffCodec[i].codecId; } return CODEC_ID_NONE; }
uint8_t lavMuxer::open(const char *filename,uint32_t inbitrate, ADM_MUXER_TYPE type, aviInfo *info,uint32_t videoExtraDataSize, uint8_t *videoExtraData, WAVHeader *audioheader,uint32_t audioextraSize,uint8_t *audioextraData) { AVCodecContext *c; _type=type; _fps1000=info->fps1000; switch(_type) { case MUXER_TS: fmt=guess_format("mpegts", NULL, NULL); break; case MUXER_DVD: fmt = guess_format("dvd", NULL, NULL); break; case MUXER_VCD: fmt = guess_format("vcd", NULL, NULL); break; case MUXER_SVCD: fmt = guess_format("svcd", NULL, NULL); break; case MUXER_MP4: fmt = guess_format("mp4", NULL, NULL); break; case MUXER_PSP: fmt = guess_format("psp", NULL, NULL); break; default: fmt=NULL; } if (!fmt) { printf("Lav:Cannot guess format\n"); return 0; } oc = av_alloc_format_context(); if (!oc) { printf("Lav:Cannot allocate context\n"); return 0; } oc->oformat = fmt; snprintf(oc->filename,1000,"file://%s",filename); // Video //________ video_st = av_new_stream(oc, 0); if (!video_st) { printf("Lav: new stream failed\n"); return 0; } c = video_st->codec; switch(_type) { case MUXER_MP4: if(isMpeg4Compatible(info->fcc)) { c->codec_id = CODEC_ID_MPEG4; c->has_b_frames=1; // in doubt... }else { if(isH264Compatible(info->fcc)) { c->has_b_frames=1; // in doubt... c->codec_id = CODEC_ID_H264; c->codec=new AVCodec; memset(c->codec,0,sizeof(AVCodec)); c->codec->name=ADM_strdup("H264"); } else { c->codec_id = CODEC_ID_MPEG4; // Default value printf("Ooops, cant mux that...\n"); printf("Ooops, cant mux that...\n"); printf("Ooops, cant mux that...\n"); //return 0; } } if(videoExtraDataSize) { c->extradata=videoExtraData; c->extradata_size= videoExtraDataSize; } c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; break; case MUXER_TS: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; break; case MUXER_DVD: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; break; case MUXER_VCD: c->codec_id = CODEC_ID_MPEG1VIDEO; c->rc_buffer_size=8*1024*40; c->rc_max_rate=1152*1000; c->rc_min_rate=1152*1000; c->bit_rate=1152*1000; break; case MUXER_SVCD: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*112; c->rc_max_rate=2500*1000; c->rc_min_rate=0*1000; if(!inbitrate) c->bit_rate=2040*1000; else c->bit_rate=inbitrate; break; default: ADM_assert(0); } c->codec_type = CODEC_TYPE_VIDEO; c->flags=CODEC_FLAG_QSCALE; c->width = info->width; c->height = info->height; switch(_fps1000) { case 25000: c->time_base= (AVRational){1001,25025}; //c->frame_rate = 25025; //c->frame_rate_base = 1001; break; case 23976: /* c->frame_rate = 24000; c->frame_rate_base = 1001; break; */ if(_type==MUXER_MP4) { c->time_base= (AVRational){1001,24000}; break; } case 29970: c->time_base= (AVRational){1001,30000}; //c->frame_rate = 30000; //c->frame_rate_base = 1001; break; default: if(_type==MUXER_MP4) { c->time_base= (AVRational){1000,_fps1000}; break; } else { GUI_Error_HIG(_("Incompatible frame rate"), NULL); return 0; } } c->gop_size=15; c->max_b_frames=2; c->has_b_frames=1; // Audio //________ if(audioheader) { audio_st = av_new_stream(oc, 1); if (!audio_st) { printf("Lav: new stream failed\n"); return 0; } c = audio_st->codec; c->frame_size=1024; //For AAC mainly, sample per frame switch(audioheader->encoding) { case WAV_AC3: c->codec_id = CODEC_ID_AC3;break; case WAV_MP2: c->codec_id = CODEC_ID_MP2;break; case WAV_MP3: #warning FIXME : Probe deeper c->frame_size=1152; c->codec_id = CODEC_ID_MP3; break; case WAV_PCM: // One chunk is 10 ms (1/100 of fq) c->frame_size=4; c->codec_id = CODEC_ID_PCM_S16LE;break; case WAV_AAC: c->extradata=audioextraData; c->extradata_size= audioextraSize; c->codec_id = CODEC_ID_AAC; break; default: printf("Cant mux that ! audio\n"); printf("Cant mux that ! audio\n"); c->codec_id = CODEC_ID_MP2; return 0; break; } c->codec_type = CODEC_TYPE_AUDIO; c->bit_rate = audioheader->byterate*8; c->rc_buffer_size=(c->bit_rate/(2*8)); // 500 ms worth _audioFq=c->sample_rate = audioheader->frequency; c->channels = audioheader->channels; _audioByterate=audioheader->byterate; } // /audio //---------------------- switch(_type) { case MUXER_MP4: oc->mux_rate=10080*1000; // Needed ? break; case MUXER_TS: oc->mux_rate=10080*1000; break; case MUXER_DVD: oc->packet_size=2048; oc->mux_rate=10080*1000; break; case MUXER_VCD: oc->packet_size=2324; oc->mux_rate=2352 * 75 * 8; break; case MUXER_SVCD: oc->packet_size=2324; oc->mux_rate=2*2352 * 75 * 8; // ? break; default: ADM_assert(0); } oc->preload=AV_TIME_BASE/10; // 100 ms preloading oc->max_delay=200*1000; // 500 ms if (av_set_parameters(oc, NULL) < 0) { printf("Lav: set param failed \n"); return 0; } if (url_fopen(&(oc->pb), filename, URL_WRONLY) < 0) { printf("Lav: Failed to open file :%s\n",filename); return 0; } av_write_header(oc); dump_format(oc, 0, filename, 1); printf("lavformat mpeg muxer initialized\n"); _running=1; one=(1000*1000*1000)/_fps1000; _curDTS=one; return 1; }
uint8_t lavMuxer::open(const char *filename,uint32_t inbitrate, ADM_MUXER_TYPE type, aviInfo *info, uint32_t videoExtraDataSize, uint8_t *videoExtraData, WAVHeader *audioheader, uint32_t audioextraSize,uint8_t *audioextraData) { AVCodecContext *c; _type=type; _fps1000=info->fps1000; switch(_type) { case MUXER_TS: fmt=guess_format("mpegts", NULL, NULL); break; case MUXER_DVD: fmt = guess_format("dvd", NULL, NULL); break; case MUXER_VCD: fmt = guess_format("vcd", NULL, NULL); break; case MUXER_SVCD: fmt = guess_format("svcd", NULL, NULL); break; case MUXER_MP4: fmt = guess_format("mp4", NULL, NULL); break; case MUXER_PSP: fmt = guess_format("psp", NULL, NULL); break; case MUXER_FLV: fmt = guess_format("flv", NULL, NULL); break; case MUXER_MATROSKA: fmt = guess_format("matroska", NULL, NULL); break; default: fmt=NULL; } if (!fmt) { printf("Lav:Cannot guess format\n"); ADM_assert(0); return 0; } oc = av_alloc_format_context(); if (!oc) { printf("Lav:Cannot allocate context\n"); return 0; } oc->oformat = fmt; snprintf(oc->filename,1000,"file://%s",filename); // Video //________ video_st = av_new_stream(oc, 0); if (!video_st) { printf("Lav: new stream failed\n"); return 0; } c = video_st->codec; switch(_type) { case MUXER_FLV: c->codec=new AVCodec; memset(c->codec,0,sizeof(AVCodec)); if(fourCC::check(info->fcc,(uint8_t *)"FLV1")) { c->codec_id=CODEC_ID_FLV1; c->codec->name=ADM_strdup("FLV1"); }else { if(fourCC::check(info->fcc,(uint8_t *)"VP6F")) { c->codec_id=CODEC_ID_VP6F; c->codec->name=ADM_strdup("VP6F"); } else ADM_assert(0); } break; case MUXER_MATROSKA: strcpy(oc->title,"Avidemux"); strcpy(oc->author,"Avidemux"); c->sample_aspect_ratio.num=1; c->sample_aspect_ratio.den=1; if(isMpeg4Compatible(info->fcc)) { c->codec_id = CODEC_ID_MPEG4; c->has_b_frames=1; // in doubt... }else { if(isH264Compatible(info->fcc)) { c->has_b_frames=1; // in doubt... c->codec_id = CODEC_ID_H264; c->codec=new AVCodec; memset(c->codec,0,sizeof(AVCodec)); c->codec->name=ADM_strdup("H264"); } else { if(!ADM_4cc_to_lavcodec((const char *)&(info->fcc),&(c->codec_id))) { printf("[lavFormat] Cannot map this\n"); return 0; } } } if(videoExtraDataSize) { c->extradata=videoExtraData; c->extradata_size= videoExtraDataSize; } break; case MUXER_MP4: case MUXER_PSP: { // probably a memeleak here char *foo=ADM_strdup(filename); strcpy(oc->title,ADM_GetFileName(foo)); strcpy(oc->author,"Avidemux"); c->sample_aspect_ratio.num=1; c->sample_aspect_ratio.den=1; if(isMpeg4Compatible(info->fcc)) { c->codec_id = CODEC_ID_MPEG4; c->has_b_frames=1; // in doubt... }else { if(isH264Compatible(info->fcc)) { c->has_b_frames=1; // in doubt... c->codec_id = CODEC_ID_H264; c->codec=new AVCodec; memset(c->codec,0,sizeof(AVCodec)); c->codec->name=ADM_strdup("H264"); } else { if(isDVCompatible(info->fcc)) { c->codec_id = CODEC_ID_DVVIDEO; }else { if(fourCC::check(info->fcc,(uint8_t *)"H263")) { c->codec_id=CODEC_ID_H263; }else{ c->codec_id = CODEC_ID_MPEG4; // Default value printf("Ooops, cant mux that...\n"); printf("Ooops, cant mux that...\n"); printf("Ooops, cant mux that...\n"); } } } } if(videoExtraDataSize) { c->extradata=videoExtraData; c->extradata_size= videoExtraDataSize; } if(MUXER_PSP==_type) { c->rc_buffer_size=0; //8*1024*224; c->rc_max_rate=0; //768*1000; c->rc_min_rate=0; c->bit_rate=768*1000; } else { c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; } } break; case MUXER_TS: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; break; case MUXER_DVD: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; break; case MUXER_VCD: c->codec_id = CODEC_ID_MPEG1VIDEO; c->rc_buffer_size=8*1024*40; c->rc_max_rate=1152*1000; c->rc_min_rate=1152*1000; c->bit_rate=1152*1000; break; case MUXER_SVCD: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*112; c->rc_max_rate=2500*1000; c->rc_min_rate=0*1000; if(!inbitrate) c->bit_rate=2040*1000; else c->bit_rate=inbitrate; break; default: ADM_assert(0); } c->codec_type = CODEC_TYPE_VIDEO; c->flags=CODEC_FLAG_QSCALE; c->width = info->width; c->height = info->height; AVRational fps25=(AVRational){1001,25025}; AVRational fps24=(AVRational){1001,24000}; AVRational fps30= (AVRational){1001,30000}; AVRational fpsfree= (AVRational){1000,_fps1000}; switch(_fps1000) { case 25000: { c->time_base= fps25; break; } case 23976: if(_type==MUXER_MP4 || _type==MUXER_PSP || _type==MUXER_FLV || _type==MUXER_MATROSKA) { c->time_base= fps24; //(AVRational){1001,24000}; break; } case 29970: c->time_base=fps30; break; default: { if(_type==MUXER_MP4 || _type==MUXER_PSP || _type==MUXER_FLV || _type==MUXER_MATROSKA) { c->time_base=fpsfree;// (AVRational){1000,_fps1000}; break; } else { GUI_Error_HIG(QT_TR_NOOP("Incompatible frame rate"), NULL); return 0; } } break; } c->gop_size=15; c->max_b_frames=2; c->has_b_frames=1; // Audio //________ if(audioheader) { audio_st = av_new_stream(oc, 1); if (!audio_st) { printf("Lav: new stream failed\n"); return 0; } c = audio_st->codec; c->frame_size=1024; //For AAC mainly, sample per frame printf("[LavFormat] Bitrate %u\n",(audioheader->byterate*8)/1000); _audioFq=c->sample_rate = audioheader->frequency; #if 0 if(_type== MUXER_PSP && audioheader->encoding==WAV_AAC) { _audioFq=c->sample_rate = audioheader->frequency/2; //_audioFq*=2; // SBR } #endif switch(audioheader->encoding) { case WAV_AC3: c->codec_id = CODEC_ID_AC3;break; case WAV_MP2: c->codec_id = CODEC_ID_MP2;break; case WAV_MP3: #warning FIXME : Probe deeper c->frame_size=1152; c->codec_id = CODEC_ID_MP3; break; case WAV_PCM: // One chunk is 10 ms (1/100 of fq) c->frame_size=4; c->codec_id = CODEC_ID_PCM_S16LE;break; case WAV_AAC: c->extradata=audioextraData; c->extradata_size= audioextraSize; c->codec_id = CODEC_ID_AAC; break; default: if(_type==MUXER_MATROSKA) { if(ADM_WaveTag_to_lavcodec(audioheader->encoding, &(c->codec_id))) { if(audioextraData) { c->extradata=audioextraData; c->extradata_size= audioextraSize; } // Put a dummy time increment c->time_base= fps25; break; } } printf("Cant mux that ! audio\n"); printf("Cant mux that ! audio\n"); c->codec_id = CODEC_ID_MP2; return 0; break; } c->codec_type = CODEC_TYPE_AUDIO; c->bit_rate = audioheader->byterate*8; c->rc_buffer_size=(c->bit_rate/(2*8)); // 500 ms worth c->channels = audioheader->channels; _audioByterate=audioheader->byterate; } // /audio //---------------------- switch(_type) { case MUXER_FLV: case MUXER_PSP: case MUXER_MP4: case MUXER_MATROSKA: oc->mux_rate=10080*1000; // Needed ? break; case MUXER_TS: oc->mux_rate=10080*1000; break; case MUXER_DVD: oc->packet_size=2048; oc->mux_rate=10080*1000; break; case MUXER_VCD: oc->packet_size=2324; oc->mux_rate=2352 * 75 * 8; break; case MUXER_SVCD: oc->packet_size=2324; oc->mux_rate=2*2352 * 75 * 8; // ? break; default: ADM_assert(0); } oc->preload=AV_TIME_BASE/10; // 100 ms preloading oc->max_delay=200*1000; // 500 ms if (av_set_parameters(oc, NULL) < 0) { printf("Lav: set param failed \n"); return 0; } if (url_fopen(&(oc->pb), filename, URL_WRONLY) < 0) { printf("Lav: Failed to open file :%s\n",filename); return 0; } ADM_assert(av_write_header(oc)>=0); dump_format(oc, 0, filename, 1); printf("lavformat mpeg muxer initialized\n"); _running=1; one=(1000*1000*1000)/_fps1000; _curDTS=one; return 1; }
/** \fn bFrameDroppable */ static bool bFrameDroppable(uint32_t fcc) { if(isH264Compatible(fcc)) return false; return true; }
bool muxerMp4v2::open(const char *file, ADM_videoStream *s,uint32_t nbAudioTrack,ADM_audioStream **a) { audioDelay=s->getVideoDelay(); vStream=s; nbAStreams=nbAudioTrack; aStreams=a; videoBufferSize=vStream->getWidth()*vStream->getHeight()*3; videoBuffer[0]=new uint8_t[videoBufferSize]; videoBuffer[1]=new uint8_t[videoBufferSize]; scratchBuffer=new uint8_t[videoBufferSize]; in[0].bufferSize=videoBufferSize; in[0].data=videoBuffer[0]; in[1].bufferSize=videoBufferSize; in[1].data=videoBuffer[1]; targetFileName=string(file); //------Verify everything is ok : Accept Mp4 & H264 for video, AAC for audio ---- uint32_t fcc=vStream->getFCC(); if(!isH264Compatible(fcc) && !isMpeg4Compatible(fcc)) { ADM_error("[mp4v2] Only h264 and mp4 video track!\n"); return false; } for(int i=0;i<nbAStreams;i++) { int encoding=aStreams[i]->getInfo()->encoding; switch(encoding) { case WAV_MP2:case WAV_MP3:case WAV_AAC:case WAV_AC3: continue; default: GUI_Error_HIG("Audio","Audio format not supported, only AAC/MP3/AC3"); return false; } } //------Verify everything is ok : Accept Mp4 & H264 for video, AAC for audio ---- // Create file handle=MP4Create( file, ADM_MP4_OPTIONS_OPEN); if(MP4_INVALID_FILE_HANDLE==handle) { ADM_error("[mp4v2]Cannot create output file %s\n",file); return false; } MP4LogSetLevel(MP4_LOG_INFO); if (!(MP4SetTimeScale( handle, 90*1000 ))) // 90 kHz tick { ADM_error("[mp4v2]Cannot set timescale to us\n"); return false; } if(false==initVideo()) { ADM_error("Cannot init video\n"); return false; } if(false==initAudio()) { ADM_error("Cannot init audio\n"); return false; } return true; er: return false; }
/** \fn getDecoder \brief returns the correct decoder for a stream w,h,fcc,extraLen,extraData,bpp */ decoders *ADM_getDecoder (uint32_t fcc, uint32_t w, uint32_t h, uint32_t extraLen, uint8_t * extraData,uint32_t bpp) { ADM_info("\nSearching decoder in plugins\n"); decoders *fromPlugin=tryCreatingVideoDecoder(w,h,fcc,extraLen,extraData,bpp); if(fromPlugin) return fromPlugin; #if defined(USE_VDPAU) ADM_info("Searching decoder in vdpau (%d x %d, extradataSize:%d)...\n",w,h,extraLen); if (isH264Compatible (fcc) || isMpeg12Compatible(fcc) || 1*isVC1Compatible(fcc)) { ADM_info("This is vdpau compatible\n"); if(true==vdpauUsable()) { decoderFFVDPAU *dec=new decoderFFVDPAU (w,h,fcc,extraLen,extraData,bpp); if(dec->initializedOk()==true) return (decoders *) (dec); else { GUI_Error_HIG("VDPAU","Cannot initialize VDPAU, make sure it is not already used by another application.\nSwitching to default decoder."); delete dec; } }else ADM_info("Vdpau is not active\n"); } #endif // VDPAU #if defined(USE_XVBA) ADM_info("Searching decoder in xvba (%d x %d, extradataSize:%d)...\n",w,h,extraLen); if (isH264Compatible (fcc) ) { ADM_info("This is xvba compatible\n"); if(true==xvbaUsable()) { decoderFFXVBA *dec=new decoderFFXVBA (w,h,fcc,extraLen,extraData,bpp); if(dec->initializedOk()==true) return (decoders *) (dec); else { GUI_Error_HIG("XVBA","Cannot initialize XVBA, make sure it is not already used by another application.\nSwitching to default decoder."); delete dec; } }else ADM_info("XVBA is not active\n"); } #endif // XVBA #if defined(USE_LIBVA) ADM_info("Searching decoder in libva (%d x %d, extradataSize:%d)...\n",w,h,extraLen); if (isH264Compatible (fcc) ) { ADM_info("This is libva compatible\n"); if(true==libvaUsable()) { decoderFFLIBVA *dec=new decoderFFLIBVA (w,h,fcc,extraLen,extraData,bpp); if(dec->initializedOk()==true) return (decoders *) (dec); else { GUI_Error_HIG("LIBVA","Cannot initialize LIBVA, make sure it is not already used by another application.\nSwitching to default decoder."); delete dec; } }else ADM_info("LIBVA is not active\n"); } #endif // XVBA ADM_info("Searching decoder in coreVideoCodec(%d x %d, extradataSize:%d)...\n",w,h,extraLen); return ADM_coreCodecGetDecoder(fcc,w,h,extraLen,extraData,bpp); }
/** \fn initVideo \brief setup video part of muxer */ bool muxerFFmpeg::initVideo(ADM_videoStream *stream) { audioDelay=stream->getVideoDelay(); video_st = avformat_new_stream(oc, NULL); if (!video_st) { printf("[FF] new stream failed\n"); return false; } AVCodecContext *c; c = video_st->codec; c->sample_aspect_ratio.num=1; c->sample_aspect_ratio.den=1; video_st->sample_aspect_ratio=c->sample_aspect_ratio; uint32_t videoExtraDataSize=0; uint8_t *videoExtraData; stream->getExtraData(&videoExtraDataSize,&videoExtraData); printf("[FF] Using %d bytes for video extradata\n",(int)videoExtraDataSize); ffmpuxerSetExtradata(c,videoExtraDataSize,videoExtraData); c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; c->bit_rate=9000*1000; c->codec_type = AVMEDIA_TYPE_VIDEO; c->flags=CODEC_FLAG_QSCALE; c->width = stream->getWidth(); c->height =stream->getHeight(); uint32_t fcc=stream->getFCC(); if(isMpeg4Compatible(fcc)) { c->codec_id = CODEC_ID_MPEG4; if(stream->providePts()==true) { c->has_b_frames=1; // in doubt... c->max_b_frames=2; }else { ADM_warning("Incoming stream does not provide PTS \n"); c->has_b_frames=0; // No PTS=cannot handle CTS... c->max_b_frames=0; } }else { if(isH264Compatible(fcc) || isH265Compatible(fcc)) { if(stream->providePts()==true) { c->has_b_frames=1; // in doubt... c->max_b_frames=2; }else { printf("[MP4] Source video has no PTS information, assuming no b frames\n"); c->has_b_frames=0; // No PTS=cannot handle CTS... c->max_b_frames=0; } if(isH265Compatible(fcc)) { c->codec_id = AV_CODEC_ID_HEVC; setAvCodec(c,AV_CODEC_ID_HEVC); } else { c->codec_id = CODEC_ID_H264; setAvCodec(c,CODEC_ID_H264); } } else { if(isDVCompatible(fcc)) { c->codec_id = CODEC_ID_DVVIDEO; }else { if(fourCC::check(fcc,(uint8_t *)"H263")) { c->codec_id=CODEC_ID_H263; }else if(isVP6Compatible(stream->getFCC())) { c->codec_id=CODEC_ID_VP6F; setAvCodec(c,CODEC_ID_VP6F); c->has_b_frames=0; // No PTS=cannot handle CTS... c->max_b_frames=0; }else if(fourCC::check(stream->getFCC(),(uint8_t *)"FLV1")) { c->has_b_frames=0; // No PTS=cannot handle CTS... c->max_b_frames=0; c->codec_id=CODEC_ID_FLV1; setAvCodec(c,CODEC_ID_FLV1); }else { if(fourCC::check(stream->getFCC(),(uint8_t *)"MPEG1")) { c->has_b_frames=1; // No PTS=cannot handle CTS... c->max_b_frames=2; c->codec_id=CODEC_ID_MPEG1VIDEO; } else if(fourCC::check(stream->getFCC(),(uint8_t *)"MPEG2")) { c->has_b_frames=1; // No PTS=cannot handle CTS... c->max_b_frames=2; c->codec_id=CODEC_ID_MPEG2VIDEO; }else { uint32_t id=stream->getFCC(); AVCodecID cid=ADM_codecIdFindByFourcc(fourCC::tostring(id)); if(cid==CODEC_ID_NONE) { printf("[FF] Unknown video codec\n"); return false; } c->codec_id=cid; } } } } } if(useGlobalHeader()==true) { if(videoExtraDataSize) { ADM_info("Video has extradata and muxer requires globalHeader, assuming it is done so.\n"); c->flags|=CODEC_FLAG_GLOBAL_HEADER; }else { ADM_warning("Video has no extradata but muxer requires globalHeader.\n"); } } printf("[FF] Video initialized\n"); return true; }
/** \fn setupVideo \brief prepare video (copy or process) */ ADM_videoStream *admSaver::setupVideo(void) { ADM_videoStream *video=NULL; // Video Stream if(!videoEncoderIndex) // Copy { aviInfo info; video_body->getVideoInfo(&info); uint8_t *extra; uint32_t extraLen; video_body->getExtraHeaderData(&extraLen,&extra); //#warning do something better ADM_videoStreamCopy *copy=NULL; if(isH264Compatible(info.fcc)) { if(muxer->preferH264AnnexB()) { ADM_info("The video stream is H264\n"); ADM_info("The muxer prefers AnnexB H264 bitstream\n"); } } if(isH264Compatible(info.fcc) && !extraLen && !muxer->preferH264AnnexB()) { ADM_info("Probably AnnexB bitstream\n"); copy=new ADM_videoStreamCopyFromAnnexB(markerA,markerB); }else { copy=new ADM_videoStreamCopy(markerA,markerB); } video=copy; // In that case, get the real time and update audio with it... // Because we might have go back in time to catch the first intra startAudioTime=copy->getStartTime(); }else { // 1- create filter chain //****************************** chain=createVideoFilterChain(markerA,markerB); if(!chain) { GUI_Error_HIG("Video","Cannot instantiante video Chain"); return NULL; } // 2- Create Encoder //******************** int sz=chain->size(); ADM_assert(sz); ADM_coreVideoFilter *last; last=(*chain)[sz-1]; // Grab last filter ADM_coreVideoEncoder *encoder=createVideoEncoderFromIndex(last,videoEncoderIndex,muxer->useGlobalHeader()); // FIXME GLOBAL HEADERS if(!encoder) { GUI_Error_HIG("Video","Cannot create encoder"); return NULL; } // 3 dual Pass ? //***************** if(encoder->isDualPass()) { encoder=handleFirstPass(encoder); // Do pass 1 and switch to pass 2 if(!encoder) { printf("[Save] cannot create encoder for pass 2\n"); return NULL; } } if(encoder->setup()==false) { GUI_Error_HIG("Video","Cannot setup codec. Bitrate too low ?"); delete encoder; encoder=NULL; return NULL; } video= new ADM_videoStreamProcess(encoder); if(!video) { GUI_Error_HIG("Video","Cannot create encoder"); delete encoder; return NULL; } } return video; }
/** \fn getDecoder \brief returns the correct decoder for a stream w,h,fcc,extraLen,extraData,bpp */ decoders *ADM_coreCodecGetDecoder (uint32_t fcc, uint32_t w, uint32_t h, uint32_t extraLen, uint8_t * extraData,uint32_t bpp) { ADM_info("Searching decoder in coreVideoCodec(%d x %d, extradataSize:%d)...\n",w,h,extraLen); if (isMSMpeg4Compatible (fcc) == 1) { return (decoders *) (new decoderFFDiv3 (w,h,fcc,extraLen,extraData,bpp)); } if (isDVCompatible(fcc))//"CDVC")) { return (decoders *) (new decoderFFDV (w,h,fcc,extraLen,extraData,bpp)); } if (fourCC::check (fcc, (uint8_t *) "HFYU")) { return (decoders *) (new decoderFFhuff (w,h,fcc,extraLen,extraData,bpp)); } if (fourCC::check (fcc, (uint8_t *) "PNG ")) { return (decoders *) (new decoderFFPng (w,h,fcc,extraLen,extraData,bpp)); } if (fourCC::check (fcc, (uint8_t *) "FFVH")) { return (decoders *) (new decoderFF_ffhuff (w,h,fcc,extraLen,extraData,bpp)); } if (isH264Compatible (fcc)) { #if defined(USE_VDPAU) && 0 if(vdpauUsable()==true) return (decoders *) (new decoderFFVDPAU (w,h,fcc,extraLen,extraData,bpp)); else #endif return (decoders *) (new decoderFFH264 (w,h,fcc,extraLen,extraData,bpp)); } /* Could be either divx5 packed crap or xvid or ffmpeg For now we return FFmpeg and later will switch to divx5 if available (ugly hack for ugly hack....) */ if (isMpeg4Compatible (fcc) == 1) { return (decoders *) (new decoderFFMpeg4 (w,h,fcc,extraLen,extraData,bpp)); } if (fourCC::check (fcc, (uint8_t *) "YV12") || fourCC::check (fcc, (uint8_t *) "yv12") || fourCC::check (fcc, (uint8_t *) "I420")) { printf ("\n using null codec\n"); return (decoders *) (new decoderNull (w,h,fcc,extraLen,extraData,bpp)); } if (fourCC::check (fcc, (uint8_t *) "UYVY")) { printf ("\n using uyvy codec\n"); return (decoders *) (new decoderUYVY (w,h,fcc,extraLen,extraData,bpp)); } if (fourCC::check (fcc, (uint8_t *) "YUY2")) { printf ("\n using YUY2 codec\n"); return (decoders *) (new decoderYUY2 (w,h,fcc,extraLen,extraData,bpp)); } if ((fcc == 0) || fourCC::check (fcc, (uint8_t *) "RGB ")) { // RGB 16 Codecs printf ("\n using RGB codec\n"); return (decoders *) (new decoderRGB16 (w,h,fcc,extraLen,extraData,bpp)); //1 } if ((fcc == 0) || fourCC::check (fcc, (uint8_t *) "DIB ")) { // RGB 16 Codecs printf ("\n using DIB codec (%d bpp)\n",(int)bpp); return (decoders *) (new decoderRGB16 (w,h,fcc,extraLen,extraData,bpp)); //0 } if (isMpeg12Compatible (fcc)) return (decoders *) (new decoderFFMpeg12 (w,h,fcc,extraLen,extraData,bpp)); // Search ffsimple decoders *dec=admCreateFFSimple(w,h,fcc,extraLen,extraData,bpp); if(dec) { printf("using ffSimple\n"); return dec; } // default : null decoder printf ("\n using invalid codec for \n"); fourCC::print (fcc); return (decoders *) (new decoderEmpty(w,h,fcc,extraLen,extraData,bpp)); }
bool muxerMP4::open(const char *file, ADM_videoStream *s,uint32_t nbAudioTrack,ADM_audioStream **a) { if(!isMpeg4Compatible(s->getFCC()) && !isH264Compatible(s->getFCC())) { GUI_Error_HIG("Unsupported","Only MP4Video & H264 supported for video"); return false; } if(nbAudioTrack) for(int i=0; i<nbAudioTrack; i++) { uint32_t acc=a[i]->getInfo()->encoding; if(acc!=WAV_MP2 && acc!=WAV_MP3 && acc!=WAV_AAC) { GUI_Error_HIG("Unsupported","Only AAC & mpegaudio supported for audio"); return false; } } /* All seems fine, open stuff */ const char *f="mp4"; if(muxerConfig.muxerType==MP4_MUXER_PSP) f="psp"; if(false==setupMuxer(f,file)) { printf("[MP4] Failed to open muxer\n"); return false; } if(initVideo(s)==false) { printf("[MP4] Failed to init video\n"); return false; } AVCodecContext *c; AVRational myTimeBase; c = video_st->codec; rescaleFps(s->getAvgFps1000(),&(c->time_base)); myTimeBase=video_st->time_base=c->time_base; ADM_info("Video stream time base :%d,%d\n",video_st->time_base.num,video_st->time_base.den); c->gop_size=15; if(initAudio(nbAudioTrack,a)==false) { printf("[MP4] Failed to init audio\n"); return false; } // /audio int er = avio_open(&(oc->pb), file, AVIO_FLAG_WRITE); ADM_info("Timebase In = %d/%d\n",myTimeBase.num,myTimeBase.den); if (er) { ADM_error("[Mp4]: Failed to open file :%s, er=%d\n",file,er); return false; } AVDictionary *dict = NULL; char buf[64]; snprintf(buf, sizeof(buf), "%d", AV_TIME_BASE / 10); av_dict_set(&dict, "preload", buf, 0); av_dict_set(&dict, "max_delay", "200000", 0); av_dict_set(&dict, "muxrate", "10080000", 0); #ifndef _WIN32 // does not work on windows as the file must be opened twice at the same time av_dict_set(&dict, "movflags","faststart",0); #endif ADM_assert(avformat_write_header(oc, &dict) >= 0); ADM_info("Timebase codec = %d/%d\n",c->time_base.num,c->time_base.den); ADM_info("Timebase stream = %d/%d\n",video_st->time_base.num,video_st->time_base.den); if(myTimeBase.den==video_st->time_base.den && video_st->time_base.num==1) { roundup=myTimeBase.num; ADM_warning("Timebase roundup = %d\n",roundup); } av_dict_free(&dict); vStream=s; aStreams=a; nbAStreams=nbAudioTrack; initialized=true; return true; }