void VideoStream::SetupFormat( const char *p_filename, const char *p_format ) { filename = p_filename; format = p_format; /* auto detect the output format from the name. default is mpeg. */ of = guess_format( format, NULL, NULL); if ( !of ) { Warning( "Could not deduce output format from file extension: using mpeg" ); of = guess_format("mpeg", NULL, NULL); } if ( !of ) { Fatal( "Could not find suitable output format" ); } /* allocate the output media context */ ofc = (AVFormatContext *)av_mallocz(sizeof(AVFormatContext)); if ( !ofc ) { Fatal( "Memory error" ); } ofc->oformat = of; snprintf( ofc->filename, sizeof(ofc->filename), "%s", filename ); }
UINT CFlvUtils::Init() { HRESULT hr = S_OK; if (!m_szFlvFile) hr = E_FAIL; if (SUCCEEDED(hr)) { // Must be called before using avcodec lib avcodec_init(); // Initialize libavcodec // and register all formats and codecs av_register_all(); } if (SUCCEEDED(hr)) { //Auto detect the output format from the name. Default is flv. m_pAVOutputFormat = guess_format(NULL, m_szFlvFile, NULL); if (!m_pAVOutputFormat) { _tprintf(_T("Could not deduce output format from file extension: using FLV.\n")); m_pAVOutputFormat = guess_format("flv", NULL, NULL); } if (!m_pAVOutputFormat) { _ftprintf(stderr, _T("Error in CFlvUtils::Init():\n Could not find suitable output format!\n")); hr = E_FAIL; // TODO: error handling? } } if (SUCCEEDED(hr)) { // Allocate the output media context m_pAVFormatContext = av_alloc_format_context(); if (!m_pAVFormatContext) { _ftprintf(stderr, _T("Error in CFlvUtils::Init():\n Could not allocate the output media context!\n")); hr = E_FAIL; // TODO: error handling? } else { m_pAVFormatContext->oformat = m_pAVOutputFormat; //_sntprintf(m_pAVFormatContext->filename, sizeof(m_pAVFormatContext->filename), _T("%s"), m_szFlvFile); _snprintf(m_pAVFormatContext->filename, sizeof(m_pAVFormatContext->filename), "%s", m_szFlvFile); } } return hr; }
status_t AVFormatWriter::Init(const media_file_format* fileFormat) { TRACE("AVFormatWriter::Init()\n"); delete[] fIOBuffer; fIOBuffer = new(std::nothrow) uint8[kIOBufferSize]; if (fIOBuffer == NULL) return B_NO_MEMORY; // Init I/O context with buffer and hook functions, pass ourself as // cookie. if (init_put_byte(&fIOContext, fIOBuffer, kIOBufferSize, 0, this, 0, _Write, _Seek) != 0) { TRACE(" init_put_byte() failed!\n"); return B_ERROR; } // Setup I/O hooks. This seems to be enough. fContext->pb = &fIOContext; // Set the AVOutputFormat according to fileFormat... fContext->oformat = guess_format(fileFormat->short_name, fileFormat->file_extension, fileFormat->mime_type); if (fContext->oformat == NULL) { TRACE(" failed to find AVOuputFormat for %s\n", fileFormat->short_name); return B_NOT_SUPPORTED; } TRACE(" found AVOuputFormat for %s: %s\n", fileFormat->short_name, fContext->oformat->name); return B_OK; }
int main() { av_register_all(); #if defined(K_LUCID) AVOutputFormat *fmt = guess_format("mpeg", NULL, NULL); #else AVOutputFormat *fmt = av_guess_format("mpeg", NULL, NULL); #endif AVFormatContext *oc = avformat_alloc_context(); oc->oformat = fmt; AVCodecContext *c; AVStream *st; st = av_new_stream(oc, 0); c = st->codec; c->time_base.den = 24; c->time_base.num = 1; c->gop_size = 12; c->pix_fmt = PIX_FMT_YUV420P; av_free(oc); return 0; }
bool CFFmpeg_Glue::IsValidVersion() { if ( !avcodec_find_encoder(CODEC_ID_AAC) || !avcodec_find_encoder(CODEC_ID_MPEG4)) { return false; } AVOutputFormat *fmt = guess_format("psp", 0, 0); if ( !fmt || strcmp(fmt->name, "psp") ) { return false; } return true; }
bool CanDoPSP() { if ( !avcodec_find_encoder(CODEC_ID_AAC) || !avcodec_find_encoder(CODEC_ID_MPEG4)) { return false; } AVOutputFormat *fmt = guess_format("psp", 0, 0); if ( !fmt || strcmp(fmt->name, "psp") ) { return false; } return true; }
bool CFFMPEGLoader::CreateMovie(const char *filename, const AVOutputFormat *format, const AVCodecContext *VideoCon, const AVCodecContext *AudioCon) { if(!filename) return false; AVOutputFormat *fmt; //*fmt=*format; fmt = guess_format(NULL, filename, NULL); pFormatCon = av_alloc_format_context(); if(!pFormatCon) { cout<<"Error while allocating format context\n"; return false; } bOutput=true; strcpy(pFormatCon->filename,filename); pFormatCon->oformat=fmt; pAudioStream=pVideoStream=NULL; if (fmt->video_codec != CODEC_ID_NONE) { pVideoStream = add_video_stream(pFormatCon, fmt->video_codec,VideoCon); } if (fmt->audio_codec != CODEC_ID_NONE) { pAudioStream = add_audio_stream(pFormatCon, fmt->audio_codec,AudioCon); } if (av_set_parameters(pFormatCon, NULL) < 0) { cout<<"Invalid output format parameters\n"; return false; } if (pVideoStream) open_stream(pFormatCon, pVideoStream); if (pAudioStream) open_stream(pFormatCon, pAudioStream); dump_format(pFormatCon, 0, filename, 1); if (!(fmt->flags & AVFMT_NOFILE)) { if (url_fopen(&pFormatCon->pb, filename, URL_WRONLY) < 0) { cout<<"Could not open '%s'"<<filename<<endl; return false; } } /* write the stream header, if any */ av_write_header(pFormatCon); return true; }
int FFMpegEncoder::configOutput() { AVOutputFormat *fmt = guess_format(profile.formatStr,NULL,NULL); if (fmt == NULL) return ERR_GUESS_FORMAT; pFormatCtx->oformat = fmt; sprintf(pFormatCtx->filename, "%s", profile.outputFilename); int ret = url_fopen(&pFormatCtx->pb, (char*)profile.outputFilename, URL_WRONLY); /* fifo_open(&pFormatCtx->pb); pFormatCtx->pb->write_packet = fifo_write; pFormatCtx->pb->seek = fifo_seek; AVFifoBuffer *fifo = getFifo(); */ return ret; }
void check_args(int argc, char **argv) { if (argc == 4) { if (strcmp(argv[1], "--order") != 0) { usage(EXIT_FAILURE); } orderspec = argv[2]; filename = argv[3]; } else if (argc == 3) { filename = argv[2]; if (strcmp(argv[1], "--auto") == 0) { /* automatically figure out format */ bank = guess_format(); } if ((strcmp(argv[1], "--hbos") == 0) || (bank == 0)) { orderspec="0,3,2,1,4"; bank = 0; } else if ((strcmp(argv[1], "--hsbc") == 0) || (bank == 1)) { orderspec="0,2,1,4,3"; bank = 1; } else { usage(EXIT_FAILURE); } } else if (argc != 2) { usage(EXIT_FAILURE); } else { filename = argv[1]; } if (setorderspec(orderspec) == -1) { fprintf(stderr, "invalid orderspec"); usage(EXIT_FAILURE); } }
int main(int argc, char **argv) { if(argc != 5) { fprintf(stderr, "Usage: %s <segment length> <output location> <filename prefix> <encoding profile>\n", argv[0]); return 1; } struct config_info config; memset(&config, 0, sizeof(struct config_info)); config.segment_length = atoi(argv[1]); config.temp_directory = argv[2]; config.filename_prefix = argv[3]; config.encoding_profile = argv[4]; config.input_filename = "pipe://1"; char *output_filename = malloc(sizeof(char) * (strlen(config.temp_directory) + 1 + strlen(config.filename_prefix) + 10)); if (!output_filename) { fprintf(stderr, "Segmenter error: Could not allocate space for output filenames\n"); exit(1); } // ------------------ Done parsing input -------------- av_register_all(); AVInputFormat *input_format = av_find_input_format("mpegts"); if (!input_format) { fprintf(stderr, "Segmenter error: Could not find MPEG-TS demuxer\n"); exit(1); } AVFormatContext *input_context = NULL; int ret = av_open_input_file(&input_context, config.input_filename, input_format, 0, NULL); if (ret != 0) { fprintf(stderr, "Segmenter error: Could not open input file, make sure it is an mpegts file: %d\n", ret); exit(1); } if (av_find_stream_info(input_context) < 0) { fprintf(stderr, "Segmenter error: Could not read stream information\n"); exit(1); } #if LIBAVFORMAT_VERSION_MAJOR >= 52 && LIBAVFORMAT_VERSION_MINOR >= 45 AVOutputFormat *output_format = av_guess_format("mpegts", NULL, NULL); #else AVOutputFormat *output_format = guess_format("mpegts", NULL, NULL); #endif if (!output_format) { fprintf(stderr, "Segmenter error: Could not find MPEG-TS muxer\n"); exit(1); } AVFormatContext *output_context = avformat_alloc_context(); if (!output_context) { fprintf(stderr, "Segmenter error: Could not allocated output context"); exit(1); } output_context->oformat = output_format; int video_index = -1; int audio_index = -1; AVStream *video_stream; AVStream *audio_stream; int i; for (i = 0; i < input_context->nb_streams && (video_index < 0 || audio_index < 0); i++) { switch (input_context->streams[i]->codec->codec_type) { case CODEC_TYPE_VIDEO: video_index = i; input_context->streams[i]->discard = AVDISCARD_NONE; video_stream = add_output_stream(output_context, input_context->streams[i]); break; case CODEC_TYPE_AUDIO: audio_index = i; input_context->streams[i]->discard = AVDISCARD_NONE; audio_stream = add_output_stream(output_context, input_context->streams[i]); break; default: input_context->streams[i]->discard = AVDISCARD_ALL; break; } } if (av_set_parameters(output_context, NULL) < 0) { fprintf(stderr, "Segmenter error: Invalid output format parameters\n"); exit(1); } dump_format(output_context, 0, config.filename_prefix, 1); if(video_index >= 0) { AVCodec *codec = avcodec_find_decoder(video_stream->codec->codec_id); if (!codec) { fprintf(stderr, "Segmenter error: Could not find video decoder, key frames will not be honored\n"); } if (avcodec_open(video_stream->codec, codec) < 0) { fprintf(stderr, "Segmenter error: Could not open video decoder, key frames will not be honored\n"); } } unsigned int output_index = 1; snprintf(output_filename, strlen(config.temp_directory) + 1 + strlen(config.filename_prefix) + 10, "%s/%s-%05u.ts", config.temp_directory, config.filename_prefix, output_index++); if (url_fopen(&output_context->pb, output_filename, URL_WRONLY) < 0) { fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename); exit(1); } if (av_write_header(output_context)) { fprintf(stderr, "Segmenter error: Could not write mpegts header to first output file\n"); exit(1); } unsigned int first_segment = 1; unsigned int last_segment = 0; double prev_segment_time = 0; int decode_done; do { double segment_time; AVPacket packet; decode_done = av_read_frame(input_context, &packet); if (decode_done < 0) { break; } if (av_dup_packet(&packet) < 0) { fprintf(stderr, "Segmenter error: Could not duplicate packet"); av_free_packet(&packet); break; } if (packet.stream_index == video_index && (packet.flags & PKT_FLAG_KEY)) { segment_time = (double)video_stream->pts.val * video_stream->time_base.num / video_stream->time_base.den; } else if (video_index < 0) { segment_time = (double)audio_stream->pts.val * audio_stream->time_base.num / audio_stream->time_base.den; } else { segment_time = prev_segment_time; } // done writing the current file? if (segment_time - prev_segment_time >= config.segment_length) { put_flush_packet(output_context->pb); url_fclose(output_context->pb); output_transfer_command(first_segment, ++last_segment, 0, config.encoding_profile); snprintf(output_filename, strlen(config.temp_directory) + 1 + strlen(config.filename_prefix) + 10, "%s/%s-%05u.ts", config.temp_directory, config.filename_prefix, output_index++); if (url_fopen(&output_context->pb, output_filename, URL_WRONLY) < 0) { fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename); break; } prev_segment_time = segment_time; } ret = av_interleaved_write_frame(output_context, &packet); if (ret < 0) { fprintf(stderr, "Segmenter error: Could not write frame of stream: %d\n", ret); } else if (ret > 0) { fprintf(stderr, "Segmenter info: End of stream requested\n"); av_free_packet(&packet); break; } av_free_packet(&packet); } while (!decode_done); av_write_trailer(output_context); if (video_index >= 0) { avcodec_close(video_stream->codec); } for(i = 0; i < output_context->nb_streams; i++) { av_freep(&output_context->streams[i]->codec); av_freep(&output_context->streams[i]); } url_fclose(output_context->pb); av_free(output_context); output_transfer_command(first_segment, ++last_segment, 1, config.encoding_profile); return 0; }
bool OStreamVideoEncoder::encoder_initialize () { char *encoding_str; // register all codecs av_register_all(); switch ( _encoding_type ) { case OSTREAM_ENCODING_MJPEG: encoding_str = "mjpeg"; _out_fmt = guess_format ( encoding_str, NULL, NULL); if( !_out_fmt ) { // DEBUG_PRINT( "Could not find suitable output format.\n"); return false; } break; case OSTREAM_ENCODING_H263P: encoding_str ="h263"; _out_fmt = guess_format ( encoding_str, NULL, NULL); if( !_out_fmt ) { // DEBUG_PRINT( "Could not find suitable output format.\n"); return false; } // specify the sub-codec we want to use. Without this we won't be able // to stream H263P not use 640x480 videos _out_fmt->video_codec = CODEC_ID_H263P; break; default: // DEBUG_PRINT ("could not find known OSTREAM_ENCODING type.\n" ); break; } _out_fmt_context = av_alloc_format_context (); if( !_out_fmt_context ) { // DEBUG_PRINT( "Memory error.\n" ); return false; } // set output format of AVFormatContext _out_fmt_context->oformat = _out_fmt; // check if we had a correct video_codec if ( _out_fmt->video_codec == CODEC_ID_NONE ) { // DEBUG_PRINT( "CODEC_ID_NONE\n" ); return false; } // add the stream if(!( _video_stream = create_video_stream( _out_fmt_context, _out_fmt->video_codec ) )) { // DEBUG_PRINT( "error in adding stream\n" ); return false; } // set the output parameters (must be done even if no parameters) if ( av_set_parameters( _out_fmt_context, NULL ) < 0 ) { // DEBUG_PRINT( "Invalid output format parameters\n" ); return false; } // open codec associated with current video_stream if ( !open_codec( _video_stream ) ) { // DEBUG_PRINT( "could not open codec\n" ); return false; } // we should now create the frame on which we can store the converted bytes // ready to be encoded _ready_to_encode_frame = create_avframe( _video_stream->codec->pix_fmt,this->_video_width,this->_video_height ); if ( !_ready_to_encode_frame ) { // DEBUG_PRINT( "Could not allocate encoded_frame\n" ); return false; } // we'll receive IplImage(s). This _opencv_frame will be converted to a stream-compatible // AVFrame [see up _ready_to_encode_frame] _opencv_frame = NULL; return true; }
OutputFormat::OutputFormat(const char* name, const char* filename): avp(guess_format(name, filename, NULL)) { if (!avp) throw(std::runtime_error("Could not guess the output format")); }
int muxer_init_muxer_lavf(muxer_t *muxer) { muxer_priv_t *priv; AVOutputFormat *fmt = NULL; char mp_filename[256] = "menc://stream.dummy"; av_register_all(); if (conf_format && strcmp(conf_format, "help") == 0) { list_formats(); return 0; } mp_msg(MSGT_MUXER, MSGL_WARN, "** MUXER_LAVF *****************************************************************\n"); if (!conf_allow_lavf) { mp_msg(MSGT_MUXER, MSGL_FATAL, "If you wish to use libavformat muxing, you must ensure that your video stream\n" "does not contain B frames (out of order decoding) and specify:\n" " -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames\n" "on the command line.\n"); } else { mp_msg(MSGT_MUXER, MSGL_WARN, "You have certified that your video stream does not contain B frames.\n"); } mp_msg(MSGT_MUXER, MSGL_WARN, "REMEMBER: MEncoder's libavformat muxing is presently broken and will generate\n" "INCORRECT files in the presence of B frames. Moreover, due to bugs MPlayer\n" "will play these INCORRECT files as if nothing were wrong!\n" "*******************************************************************************\n"); if (!conf_allow_lavf) return 0; priv = (muxer_priv_t *) calloc(1, sizeof(muxer_priv_t)); if(priv == NULL) return 0; priv->oc = av_alloc_format_context(); if(!priv->oc) { mp_msg(MSGT_MUXER, MSGL_FATAL, "Couldn't get format context\n"); goto fail; } if(conf_format) fmt = guess_format(conf_format, NULL, NULL); if(! fmt) fmt = guess_format(NULL, out_filename, NULL); if(! fmt) { mp_msg(MSGT_MUXER, MSGL_FATAL, "CAN'T GET SPECIFIED FORMAT\n"); goto fail; } priv->oc->oformat = fmt; if(av_set_parameters(priv->oc, NULL) < 0) { mp_msg(MSGT_MUXER, MSGL_FATAL, "Invalid output format parameters\n"); goto fail; } priv->oc->packet_size= mux_packet_size; priv->oc->mux_rate= mux_rate; priv->oc->preload= (int)(mux_preload*AV_TIME_BASE); priv->oc->max_delay= (int)(mux_max_delay*AV_TIME_BASE); if (info_name) pstrcpy(priv->oc->title , sizeof(priv->oc->title ), info_name ); if (info_artist) pstrcpy(priv->oc->author , sizeof(priv->oc->author ), info_artist ); if (info_genre) pstrcpy(priv->oc->genre , sizeof(priv->oc->genre ), info_genre ); if (info_copyright) pstrcpy(priv->oc->copyright, sizeof(priv->oc->copyright), info_copyright); if (info_comment) pstrcpy(priv->oc->comment , sizeof(priv->oc->comment ), info_comment ); register_protocol(&mp_protocol); if(url_fopen(&priv->oc->pb, mp_filename, URL_WRONLY)) { mp_msg(MSGT_MUXER, MSGL_FATAL, "Coulnd't open outfile\n"); goto fail; } ((URLContext*)(priv->oc->pb.opaque))->priv_data= muxer; muxer->priv = (void *) priv; muxer->cont_new_stream = &lavf_new_stream; muxer->cont_write_chunk = &write_chunk; muxer->cont_write_header = &write_header; muxer->cont_write_index = &write_trailer; muxer->fix_stream_parameters = &fix_parameters; mp_msg(MSGT_MUXER, MSGL_INFO, "OK, exit\n"); return 1; fail: free(priv); return 0; }
void VideoWriterThread::open() { av_register_all(); // TODO: make sure this is only done once. // av_log_set_level(AV_LOG_DEBUG); #if LIBAVFORMAT_VERSION_MAJOR > 52 m_pOutputFormat = av_guess_format(0, m_sFilename.c_str(), 0); #else m_pOutputFormat = guess_format(0, m_sFilename.c_str(), 0); #endif m_pOutputFormat->video_codec = CODEC_ID_MJPEG; #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 24, 0) m_pOutputFormatContext = avformat_alloc_context(); #else m_pOutputFormatContext = av_alloc_format_context(); #endif m_pOutputFormatContext->oformat = m_pOutputFormat; strncpy(m_pOutputFormatContext->filename, m_sFilename.c_str(), sizeof(m_pOutputFormatContext->filename)); if (m_pOutputFormat->video_codec != CODEC_ID_NONE) { setupVideoStream(); } #if LIBAVFORMAT_VERSION_MAJOR < 52 av_set_parameters(m_pOutputFormatContext, NULL); #endif float muxMaxDelay = 0.7; m_pOutputFormatContext->max_delay = int(muxMaxDelay * AV_TIME_BASE); // av_dump_format(m_pOutputFormatContext, 0, m_sFilename.c_str(), 1); openVideoCodec(); m_pVideoBuffer = NULL; if (!(m_pOutputFormatContext->oformat->flags & AVFMT_RAWPICTURE)) { m_pVideoBuffer = (unsigned char*)(av_malloc(VIDEO_BUFFER_SIZE)); } if (!(m_pOutputFormat->flags & AVFMT_NOFILE)) { #if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(53, 8, 0) int retVal = avio_open(&m_pOutputFormatContext->pb, m_sFilename.c_str(), URL_WRONLY); #else int retVal = url_fopen(&m_pOutputFormatContext->pb, m_sFilename.c_str(), URL_WRONLY); #endif if (retVal < 0) { throw Exception(AVG_ERR_VIDEO_INIT_FAILED, string("Could not open output file: '") + m_sFilename + "'"); } } m_pFrameConversionContext = sws_getContext(m_Size.x, m_Size.y, ::PIX_FMT_RGB32, m_Size.x, m_Size.y, STREAM_PIXEL_FORMAT, SWS_BILINEAR, NULL, NULL, NULL); m_pConvertedFrame = createFrame(STREAM_PIXEL_FORMAT, m_Size); #if LIBAVFORMAT_VERSION_MAJOR > 52 avformat_write_header(m_pOutputFormatContext, 0); #else av_write_header(m_pOutputFormatContext); #endif }
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; }
/// Create a video writer object that uses FFMPEG CV_IMPL CvVideoWriter* cvCreateVideoWriter( const char * filename, int fourcc, double fps, CvSize frameSize, int /*is_color*/ ) { CV_FUNCNAME("cvCreateVideoWriter"); CvAVI_FFMPEG_Writer * writer = NULL; __BEGIN__; // check arguments assert (filename); assert (fps > 0); assert (frameSize.width > 0 && frameSize.height > 0); // allocate memory for structure... writer = (CvAVI_FFMPEG_Writer *) cvAlloc( sizeof(CvAVI_FFMPEG_Writer)); memset (writer, 0, sizeof (*writer)); // tell FFMPEG to register codecs av_register_all (); /* auto detect the output format from the name. default is mpeg. */ writer->fmt = guess_format(NULL, filename, NULL); if (!writer->fmt) { CV_ERROR( CV_StsUnsupportedFormat, "Could not deduce output format from file extension"); //writer->fmt = guess_format("mpeg", NULL, NULL); } // alloc memory for context writer->oc = av_alloc_format_context(); assert (writer->oc); /* set file name */ writer->oc->oformat = writer->fmt; snprintf(writer->oc->filename, sizeof(writer->oc->filename), "%s", filename); // TODO -- safe to ignore output audio stream? writer->video_st = icv_add_video_stream_FFMPEG(writer->oc, fourcc, frameSize.width, frameSize.height, 800000, fps, PIX_FMT_YUV420P); /* set the output parameters (must be done even if no parameters). */ if (av_set_parameters(writer->oc, NULL) < 0) { CV_ERROR(CV_StsBadArg, "Invalid output format parameters"); } dump_format(writer->oc, 0, filename, 1); /* now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers */ if (!writer->video_st){ CV_ERROR(CV_StsBadArg, "Couldn't open video stream"); } AVCodec *codec; AVCodecContext *c; #if LIBAVFORMAT_BUILD > 4628 c = (writer->video_st->codec); #else c = &(writer->video_st->codec); #endif /* find the video encoder */ codec = avcodec_find_encoder(c->codec_id); if (!codec) { CV_ERROR(CV_StsBadArg, "codec not found"); } /* open the codec */ if (avcodec_open(c, codec) < 0) { char errtext[256]; sprintf(errtext, "Could not open codec '%s'", codec->name); CV_ERROR(CV_StsBadArg, errtext); } // printf("Using codec %s\n", codec->name); writer->outbuf = NULL; if (!(writer->oc->oformat->flags & AVFMT_RAWPICTURE)) { /* allocate output buffer */ /* XXX: API change will be done */ writer->outbuf_size = 200000; writer->outbuf = (uint8_t *) malloc(writer->outbuf_size); } bool need_color_convert; need_color_convert = c->pix_fmt != PIX_FMT_BGR24; /* allocate the encoded raw picture */ writer->picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert); if (!writer->picture) { CV_ERROR(CV_StsNoMem, "Could not allocate picture"); } /* if the output format is not YUV420P, then a temporary YUV420P picture is needed too. It is then converted to the required output format */ writer->rgb_picture = NULL; if ( need_color_convert ) { writer->rgb_picture = icv_alloc_picture_FFMPEG(PIX_FMT_BGR24, c->width, c->height, false); if (!writer->rgb_picture) { CV_ERROR(CV_StsNoMem, "Could not allocate picture"); } } /* open the output file, if needed */ if (!(writer->fmt->flags & AVFMT_NOFILE)) { if (url_fopen(&writer->oc->pb, filename, URL_WRONLY) < 0) { CV_ERROR(CV_StsBadArg, "Couldn't open output file for writing"); } } /* write the stream header, if any */ av_write_header( writer->oc ); __END__; // return what we got return (CvVideoWriter *) writer; }
//---------------------------------------------------------------- // main_utf8 // int main_utf8(int argc, char **argv) { const char *input = NULL; const char *output_prefix = ""; double target_segment_duration = 0.0; char *segment_duration_check = NULL; const char *playlist_filename = NULL; const char *http_prefix = ""; long max_tsfiles = 0; char *max_tsfiles_check = NULL; double prev_segment_time = 0.0; double segment_duration = 0.0; unsigned int output_index = 0; const AVClass *fc = avformat_get_class(); AVDictionary *format_opts = NULL; AVOutputFormat *ofmt = NULL; AVFormatContext *ic = NULL; AVFormatContext *oc = NULL; AVStream *video_st = NULL; AVStream *audio_st = NULL; AVCodec *codec = NULL; char *output_filename = NULL; char *pid_filename = NULL; int video_index = -1; int audio_index = -1; int kill_file = 0; int decode_done = 0; int ret = 0; int i = 0; TSMStreamLace * streamLace = NULL; TSMPlaylist * playlist = NULL; const double segment_duration_error_tolerance = 0.05; double extra_duration_needed = 0; int strict_segment_duration = 0; av_log_set_level(AV_LOG_INFO); for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-i") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -i parameter"); i++; input = argv[i]; } else if (strcmp(argv[i], "-o") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -i parameter"); i++; output_prefix = argv[i]; } else if (strcmp(argv[i], "-d") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -d parameter"); i++; target_segment_duration = strtod(argv[i], &segment_duration_check); if (segment_duration_check == argv[i] || target_segment_duration == HUGE_VAL || target_segment_duration == -HUGE_VAL) { usage3(argv, "invalid segment duration: ", argv[i]); } } else if (strcmp(argv[i], "-x") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -x parameter"); i++; playlist_filename = argv[i]; } else if (strcmp(argv[i], "-p") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -p parameter"); i++; http_prefix = argv[i]; } else if (strcmp(argv[i], "-w") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -w parameter"); i++; max_tsfiles = strtol(argv[i], &max_tsfiles_check, 10); if (max_tsfiles_check == argv[i] || max_tsfiles < 0 || max_tsfiles >= INT_MAX) { usage3(argv, "invalid live stream max window size: ", argv[i]); } } else if (strcmp(argv[i], "-P") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -P parameter"); i++; pid_filename = argv[i]; } else if (strcmp(argv[i], "--watch-for-kill-file") == 0) { // end program when it finds a file with name 'kill': kill_file = 1; } else if (strcmp(argv[i], "--strict-segment-duration") == 0) { // force segment creation on non-keyframe boundaries: strict_segment_duration = 1; } else if (strcmp(argv[i], "--avformat-option") == 0) { const AVOption *of; const char *opt; const char *arg; if ((argc - i) <= 1) usage(argv, "could not parse --avformat-option parameter"); i++; opt = argv[i]; if ((argc - i) <= 1) usage(argv, "could not parse --avformat-option parameter"); i++; arg = argv[i]; if ((of = av_opt_find(&fc, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) av_dict_set(&format_opts, opt, arg, (of->type == AV_OPT_TYPE_FLAGS) ? AV_DICT_APPEND : 0); else usage3(argv, "unknown --avformat-option parameter: ", opt); } else if (strcmp(argv[i], "--loglevel") == 0) { const char *arg; if ((argc - i) <= 1) usage(argv, "could not parse --loglevel parameter"); i++; arg = argv[i]; if (loglevel(arg)) usage3(argv, "unknown --loglevel parameter: ", arg); } } if (!input) { usage(argv, "-i input file parameter must be specified"); } if (!playlist_filename) { usage(argv, "-x m3u8 playlist file parameter must be specified"); } if (target_segment_duration == 0.0) { usage(argv, "-d segment duration parameter must be specified"); } // Create PID file if (pid_filename) { FILE* pid_file = fopen_utf8(pid_filename, "wb"); if (pid_file) { fprintf(pid_file, "%d", getpid()); fclose(pid_file); } } av_register_all(); avformat_network_init(); if (!strcmp(input, "-")) { input = "pipe:"; } output_filename = malloc(sizeof(char) * (strlen(output_prefix) + 15)); if (!output_filename) { fprintf(stderr, "Could not allocate space for output filenames\n"); goto error; } playlist = createPlaylist(max_tsfiles, target_segment_duration, http_prefix); if (!playlist) { fprintf(stderr, "Could not allocate space for m3u8 playlist structure\n"); goto error; } ret = avformat_open_input(&ic, input, NULL, (format_opts) ? &format_opts : NULL); if (ret != 0) { fprintf(stderr, "Could not open input file, make sure it is an mpegts or mp4 file: %d\n", ret); goto error; } av_dict_free(&format_opts); if (avformat_find_stream_info(ic, NULL) < 0) { fprintf(stderr, "Could not read stream information\n"); goto error; } #if LIBAVFORMAT_VERSION_MAJOR > 52 || (LIBAVFORMAT_VERSION_MAJOR == 52 && \ LIBAVFORMAT_VERSION_MINOR >= 45) ofmt = av_guess_format("mpegts", NULL, NULL); #else ofmt = guess_format("mpegts", NULL, NULL); #endif if (!ofmt) { fprintf(stderr, "Could not find MPEG-TS muxer\n"); goto error; } oc = avformat_alloc_context(); if (!oc) { fprintf(stderr, "Could not allocated output context\n"); goto error; } oc->oformat = ofmt; video_index = -1; audio_index = -1; for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) { switch (ic->streams[i]->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: video_index = i; ic->streams[i]->discard = AVDISCARD_NONE; video_st = add_output_stream(oc, ic->streams[i]); break; case AVMEDIA_TYPE_AUDIO: audio_index = i; ic->streams[i]->discard = AVDISCARD_NONE; audio_st = add_output_stream(oc, ic->streams[i]); break; default: ic->streams[i]->discard = AVDISCARD_ALL; break; } } av_dump_format(oc, 0, output_prefix, 1); if (video_index >=0) { codec = avcodec_find_decoder(video_st->codec->codec_id); if (!codec) { fprintf(stderr, "Could not find video decoder, key frames will not be honored\n"); } if (avcodec_open2(video_st->codec, codec, NULL) < 0) { fprintf(stderr, "Could not open video decoder, key frames will not be honored\n"); } } snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, ++output_index); if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "Could not open '%s'\n", output_filename); goto error; } if (avformat_write_header(oc, NULL)) { fprintf(stderr, "Could not write mpegts header to first output file\n"); goto error; } prev_segment_time = (double)(ic->start_time) / (double)(AV_TIME_BASE); streamLace = createStreamLace(ic->nb_streams); do { double segment_time = 0.0; AVPacket packet; double packetStartTime = 0.0; double packetDuration = 0.0; if (!decode_done) { decode_done = av_read_frame(ic, &packet); if (!decode_done) { if (packet.stream_index != video_index && packet.stream_index != audio_index) { av_free_packet(&packet); continue; } double timeStamp = (double)(packet.pts) * (double)(ic->streams[packet.stream_index]->time_base.num) / (double)(ic->streams[packet.stream_index]->time_base.den); if (av_dup_packet(&packet) < 0) { fprintf(stderr, "Could not duplicate packet\n"); av_free_packet(&packet); break; } insertPacket(streamLace, &packet, timeStamp); } } if (countPackets(streamLace) < 50 && !decode_done) { /* allow the queue to fill up so that the packets can be sorted properly */ continue; } if (!removePacket(streamLace, &packet)) { if (decode_done) { /* the queue is empty, we are done */ break; } assert(decode_done); continue; } packetStartTime = (double)(packet.pts) * (double)(ic->streams[packet.stream_index]->time_base.num) / (double)(ic->streams[packet.stream_index]->time_base.den); packetDuration = (double)(packet.duration) * (double)(ic->streams[packet.stream_index]->time_base.num) / (double)(ic->streams[packet.stream_index]->time_base.den); #if !defined(NDEBUG) && (defined(DEBUG) || defined(_DEBUG)) if (av_log_get_level() >= AV_LOG_VERBOSE) fprintf(stderr, "stream %i, packet [%f, %f)\n", packet.stream_index, packetStartTime, packetStartTime + packetDuration); #endif segment_duration = packetStartTime + packetDuration - prev_segment_time; // NOTE: segments are supposed to start on a keyframe. // If the keyframe interval and segment duration do not match // forcing the segment creation for "better seeking behavior" // will result in decoding artifacts after seeking or stream switching. if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY || strict_segment_duration)) { segment_time = packetStartTime; } else if (video_index < 0) { segment_time = packetStartTime; } else { segment_time = prev_segment_time; } if (segment_time - prev_segment_time + segment_duration_error_tolerance > target_segment_duration + extra_duration_needed) { avio_flush(oc->pb); avio_close(oc->pb); // Keep track of accumulated rounding error to account for it in later chunks. double segment_duration = segment_time - prev_segment_time; int rounded_segment_duration = (int)(segment_duration + 0.5); extra_duration_needed += (double)rounded_segment_duration - segment_duration; updatePlaylist(playlist, playlist_filename, output_filename, output_index, rounded_segment_duration); snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, ++output_index); if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "Could not open '%s'\n", output_filename); break; } // close when we find the 'kill' file if (kill_file) { FILE* fp = fopen("kill", "rb"); if (fp) { fprintf(stderr, "user abort: found kill file\n"); fclose(fp); remove("kill"); decode_done = 1; removeAllPackets(streamLace); } } prev_segment_time = segment_time; } ret = av_interleaved_write_frame(oc, &packet); if (ret < 0) { fprintf(stderr, "Warning: Could not write frame of stream\n"); } else if (ret > 0) { fprintf(stderr, "End of stream requested\n"); av_free_packet(&packet); break; } av_free_packet(&packet); } while (!decode_done || countPackets(streamLace) > 0); av_write_trailer(oc); if (video_index >= 0) { avcodec_close(video_st->codec); } for(i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]->codec); av_freep(&oc->streams[i]); } avio_close(oc->pb); av_free(oc); updatePlaylist(playlist, playlist_filename, output_filename, output_index, segment_duration); closePlaylist(playlist); releasePlaylist(&playlist); if (pid_filename) { remove(pid_filename); } return 0; error: if (pid_filename) { remove(pid_filename); } return 1; }
/// Create a video writer object that uses FFMPEG inline bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, double fps, int width, int height, bool is_color ) { icvInitFFMPEG_internal(); CodecID codec_id = CODEC_ID_NONE; int err, codec_pix_fmt; double bitrate_scale = 1; close(); // check arguments if( !filename ) return false; if(fps <= 0) return false; // we allow frames of odd width or height, but in this case we truncate // the rightmost column/the bottom row. Probably, this should be handled more elegantly, // but some internal functions inside FFMPEG swscale require even width/height. width &= -2; height &= -2; if( width <= 0 || height <= 0 ) return false; /* auto detect the output format from the name and fourcc code. */ #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) fmt = av_guess_format(NULL, filename, NULL); #else fmt = guess_format(NULL, filename, NULL); #endif if (!fmt) return false; /* determine optimal pixel format */ if (is_color) { input_pix_fmt = PIX_FMT_BGR24; } else { input_pix_fmt = PIX_FMT_GRAY8; } /* Lookup codec_id for given fourcc */ #if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0) if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE ) return false; #else const struct AVCodecTag * tags[] = { codec_bmp_tags, NULL}; if( (codec_id = av_codec_get_id(tags, fourcc)) == CODEC_ID_NONE ) return false; #endif // alloc memory for context #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) oc = avformat_alloc_context(); #else oc = av_alloc_format_context(); #endif assert (oc); /* set file name */ oc->oformat = fmt; _snprintf(oc->filename, sizeof(oc->filename), "%s", filename); /* set some options */ oc->max_delay = (int)(0.7*AV_TIME_BASE); /* This reduces buffer underrun warnings with MPEG */ // set a few optimal pixel formats for lossless codecs of interest.. switch (codec_id) { #if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0) case CODEC_ID_JPEGLS: // BGR24 or GRAY8 depending on is_color... codec_pix_fmt = input_pix_fmt; break; #endif case CODEC_ID_HUFFYUV: codec_pix_fmt = PIX_FMT_YUV422P; break; case CODEC_ID_MJPEG: case CODEC_ID_LJPEG: codec_pix_fmt = PIX_FMT_YUVJ420P; bitrate_scale = 3; break; case CODEC_ID_RAWVIDEO: codec_pix_fmt = input_pix_fmt == PIX_FMT_GRAY8 || input_pix_fmt == PIX_FMT_GRAY16LE || input_pix_fmt == PIX_FMT_GRAY16BE ? input_pix_fmt : PIX_FMT_YUV420P; break; default: // good for lossy formats, MPEG, etc. codec_pix_fmt = PIX_FMT_YUV420P; break; } double bitrate = MIN(bitrate_scale*fps*width*height, (double)INT_MAX/2); // TODO -- safe to ignore output audio stream? video_st = icv_add_video_stream_FFMPEG(oc, codec_id, width, height, (int)(bitrate + 0.5), fps, codec_pix_fmt); /* set the output parameters (must be done even if no parameters). */ #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) if (av_set_parameters(oc, NULL) < 0) { return false; } #endif #if 0 #if FF_API_DUMP_FORMAT dump_format(oc, 0, filename, 1); #else av_dump_format(oc, 0, filename, 1); #endif #endif /* now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers */ if (!video_st){ return false; } AVCodec *codec; AVCodecContext *c; #if LIBAVFORMAT_BUILD > 4628 c = (video_st->codec); #else c = &(video_st->codec); #endif c->codec_tag = fourcc; /* find the video encoder */ codec = avcodec_find_encoder(c->codec_id); if (!codec) { fprintf(stderr, "Could not find encoder for codec id %d: %s", c->codec_id, icvFFMPEGErrStr( #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) AVERROR_ENCODER_NOT_FOUND #else -1 #endif )); return false; } s64 lbit_rate = (s64)c->bit_rate; lbit_rate += (bitrate / 2); lbit_rate = std::min(lbit_rate, (s64)INT_MAX); c->bit_rate_tolerance = (int)lbit_rate; c->bit_rate = (int)lbit_rate; /* open the codec */ if ((err= #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) avcodec_open2(c, codec, NULL) #else avcodec_open(c, codec) #endif ) < 0) { fprintf(stderr, "Could not open codec '%s': %s", codec->name, icvFFMPEGErrStr(err)); return false; } outbuf = NULL; if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) { /* allocate output buffer */ /* assume we will never get codec output with more than 4 bytes per pixel... */ outbuf_size = width*height*4; outbuf = (uint8_t *) av_malloc(outbuf_size); } bool need_color_convert; need_color_convert = (c->pix_fmt != input_pix_fmt); /* allocate the encoded raw picture */ picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert); if (!picture) { return false; } /* if the output format is not our input format, then a temporary picture of the input format is needed too. It is then converted to the required output format */ input_picture = NULL; if ( need_color_convert ) { input_picture = icv_alloc_picture_FFMPEG(input_pix_fmt, c->width, c->height, false); if (!input_picture) { return false; } } /* open the output file, if needed */ if (!(fmt->flags & AVFMT_NOFILE)) { #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) #else if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) #endif { return false; } } #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0) /* write the stream header, if any */ err=avformat_write_header(oc, NULL); #else err=av_write_header( oc ); #endif if(err < 0) { close(); remove(filename); return false; } frame_width = width; frame_height = height; ok = true; return true; }
/// close video output stream and free associated memory void CvVideoWriter_FFMPEG::close() { unsigned i; // nothing to do if already released if ( !picture ) return; /* no more frame to compress. The codec has a latency of a few frames if using B frames, so we get the last frames by passing the same picture again */ // TODO -- do we need to account for latency here? /* write the trailer, if any */ av_write_trailer(oc); // free pictures #if LIBAVFORMAT_BUILD > 4628 if( video_st->codec->pix_fmt != input_pix_fmt){ #else if( video_st->codec.pix_fmt != input_pix_fmt){ #endif cvFree(&(picture->data[0])); } av_free(picture); if (input_picture) { av_free(input_picture); } /* close codec */ #if LIBAVFORMAT_BUILD > 4628 avcodec_close(video_st->codec); #else avcodec_close(&(video_st->codec)); #endif av_free(outbuf); /* free the streams */ for(i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]->codec); av_freep(&oc->streams[i]); } if (!(fmt->flags & AVFMT_NOFILE)) { /* close the output file */ #if LIBAVCODEC_VERSION_INT==((51<<16)+(49<<8)+0) url_fclose(oc->pb); #else url_fclose(&oc->pb); #endif } /* free the stream */ av_free(oc); cvReleaseImage( &temp_image ); init(); } /// Create a video writer object that uses FFMPEG bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, double fps, CvSize frameSize, bool is_color ) { CV_FUNCNAME("CvVideoWriter_FFMPEG::open"); CodecID codec_id = CODEC_ID_NONE; int err; __BEGIN__; close(); // check arguments assert (filename); assert (fps > 0); assert (frameSize.width > 0 && frameSize.height > 0); // tell FFMPEG to register codecs av_register_all (); /* auto detect the output format from the name and fourcc code. */ fmt = guess_format(NULL, filename, NULL); if (!fmt) { CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG does not recognize the given file extension"); } /* determine optimal pixel format */ if (is_color) { input_pix_fmt = PIX_FMT_BGR24; } else { input_pix_fmt = PIX_FMT_GRAY8; } // alloc memory for context oc = av_alloc_format_context(); assert (oc); /* set file name */ oc->oformat = fmt; snprintf(oc->filename, sizeof(oc->filename), "%s", filename); /* set some options */ oc->max_delay = (int)(0.7*AV_TIME_BASE); /* This reduces buffer underrun warnings with MPEG */ /* Lookup codec_id for given fourcc */ if(fourcc!=CV_FOURCC_DEFAULT){ #if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0) if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE ){ CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." ); } } #else if( (codec_id = av_codec_get_id((const AVCodecTag**)(&codec_bmp_tags), fourcc)) == CODEC_ID_NONE ){ CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." ); } }
void VideoStream::SetupFormat( ) { /* allocate the output media context */ ofc = NULL; #if ((LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 5, 0)) && (LIBAVFORMAT_VERSION_MICRO >= 100)) avformat_alloc_output_context2( &ofc, NULL, format, filename ); #else AVFormatContext *s= avformat_alloc_context(); if(!s) { Fatal( "avformat_alloc_context failed %d \"%s\"", (size_t)ofc, av_err2str((size_t)ofc) ); } AVOutputFormat *oformat; if (format) { #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 45, 0) oformat = av_guess_format(format, NULL, NULL); #else oformat = guess_format(format, NULL, NULL); #endif if (!oformat) { Fatal( "Requested output format '%s' is not a suitable output format", format ); } } else { #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 45, 0) oformat = av_guess_format(NULL, filename, NULL); #else oformat = guess_format(NULL, filename, NULL); #endif if (!oformat) { Fatal( "Unable to find a suitable output format for '%s'", format ); } } s->oformat = oformat; if (s->oformat->priv_data_size > 0) { s->priv_data = av_mallocz(s->oformat->priv_data_size); if (!s->priv_data) { Fatal( "Could not allocate private data for output format." ); } #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 92, 0) if (s->oformat->priv_class) { *(const AVClass**)s->priv_data = s->oformat->priv_class; av_opt_set_defaults(s->priv_data); } #endif } else { s->priv_data = NULL; } if(filename) { snprintf( s->filename, sizeof(s->filename), filename ); } ofc = s; #endif if ( !ofc ) { Fatal( "avformat_alloc_..._context failed: %d", ofc ); } of = ofc->oformat; Debug( 1, "Using output format: %s (%s)", of->name, of->long_name ); }
void FFMpegManager::create(const QString &filePath, int formatId, const QStringList &paths, const QSize &size, int fps) { #ifdef HAVE_FFMPEG AVOutputFormat *fmt = guess_format(0, filePath.toLatin1().data(), 0); if ( !fmt ) { fmt = guess_format("mpeg", NULL, NULL); } // AVFormatParameters params, *ap = ¶ms; switch(formatId) { case ExportInterface::ASF: { } break; case ExportInterface::AVI: { fmt->video_codec = CODEC_ID_MSMPEG4V3; // video_st->codec.codec_tag = 0; } break; case ExportInterface::MOV: { } break; case ExportInterface::MPEG: { } break; case ExportInterface::RM: { } break; case ExportInterface::SWF: { } break; case ExportInterface::GIF: { // AVImageFormat *imageFormat = guess_image_format(filePath.toLatin1().data()); // // memset(ap, 0, sizeof(*ap)); // ap->image_format = imageFormat; } break; default: break; } AVFormatContext *oc = av_alloc_format_context(); if ( !oc ) { dError() << "Error while export"; return; } oc->oformat = fmt; snprintf(oc->filename, sizeof(oc->filename), "%s", filePath.toLatin1().data()); AVStream *video_st = addVideoStream(oc, fmt->video_codec, size.width(), size.height(), fps); if ( !video_st ) { dError() << "Can't add video stream"; return; } if (av_set_parameters(oc, 0) < 0) { dError() << "Invalid output format parameters"; return ; } dump_format(oc, 0, filePath.toLatin1().data(), 1); if (!openVideo(oc, video_st) ) { dError() << "Can't open video"; return; } if (!(fmt->flags & AVFMT_NOFILE)) { if (url_fopen(&oc->pb, filePath.toLatin1().data(), URL_WRONLY) < 0) { dError() << "Could not open " << filePath.toLatin1().data(); return; } } av_write_header(oc); double video_pts = 0.0; foreach(QString imagePath, paths) { if (video_st) { video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den; } else { video_pts = 0.0; } if (!video_st || video_pts >= m_streamDuration ) { break; } if (! writeVideoFrame(imagePath, oc, video_st, fps) ) { break; } } closeVideo(oc, video_st); av_write_trailer(oc); for(int i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]); } if (!(fmt->flags & AVFMT_NOFILE)) { /* close the output file */ url_fclose(&oc->pb); } av_free(oc); #endif }
/// close video output stream and free associated memory void CvVideoWriter_FFMPEG::close() { unsigned i; // nothing to do if already released if ( !picture ) return; /* no more frame to compress. The codec has a latency of a few frames if using B frames, so we get the last frames by passing the same picture again */ // TODO -- do we need to account for latency here? /* write the trailer, if any */ av_write_trailer(oc); // free pictures #if LIBAVFORMAT_BUILD > 4628 if( video_st->codec->pix_fmt != input_pix_fmt){ #else if( video_st->codec.pix_fmt != input_pix_fmt){ #endif cvFree(&(picture->data[0])); } av_free(picture); if (input_picture) { av_free(input_picture); } /* close codec */ #if LIBAVFORMAT_BUILD > 4628 avcodec_close(video_st->codec); #else avcodec_close(&(video_st->codec)); #endif av_free(outbuf); /* free the streams */ for(i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]->codec); av_freep(&oc->streams[i]); } if (!(fmt->flags & AVFMT_NOFILE)) { /* close the output file */ #if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0) url_fclose(oc->pb); #else url_fclose(&oc->pb); #endif } /* free the stream */ av_free(oc); cvReleaseImage( &temp_image ); init(); } /// Create a video writer object that uses FFMPEG bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, double fps, CvSize frameSize, bool is_color ) { CV_FUNCNAME("CvVideoWriter_FFMPEG::open"); CodecID codec_id = CODEC_ID_NONE; int err, codec_pix_fmt, bitrate_scale=64; __BEGIN__; close(); // check arguments assert (filename); assert (fps > 0); assert (frameSize.width > 0 && frameSize.height > 0); // tell FFMPEG to register codecs av_register_all (); /* auto detect the output format from the name and fourcc code. */ fmt = guess_format(NULL, filename, NULL); if (!fmt) { CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG does not recognize the given file extension"); } /* determine optimal pixel format */ if (is_color) { input_pix_fmt = PIX_FMT_BGR24; } else { input_pix_fmt = PIX_FMT_GRAY8; } // alloc memory for context oc = av_alloc_format_context(); assert (oc); /* set file name */ oc->oformat = fmt; snprintf(oc->filename, sizeof(oc->filename), "%s", filename); /* set some options */ oc->max_delay = (int)(0.7*AV_TIME_BASE); /* This reduces buffer underrun warnings with MPEG */ /* Lookup codec_id for given fourcc */ #if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0) if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE ){ CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." ); } #else { const struct AVCodecTag * tags[] = { codec_bmp_tags, NULL}; if( (codec_id = av_codec_get_id(tags, fourcc)) == CODEC_ID_NONE ){ CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." ); } } #endif // set a few optimal pixel formats for lossless codecs of interest.. switch (codec_id) { #if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0) case CODEC_ID_JPEGLS: // BGR24 or GRAY8 depending on is_color... codec_pix_fmt = input_pix_fmt; break; #endif case CODEC_ID_HUFFYUV: codec_pix_fmt = PIX_FMT_YUV422P; break; case CODEC_ID_MJPEG: case CODEC_ID_LJPEG: codec_pix_fmt = PIX_FMT_YUVJ420P; bitrate_scale = 128; break; case CODEC_ID_RAWVIDEO: default: // good for lossy formats, MPEG, etc. codec_pix_fmt = PIX_FMT_YUV420P; break; } // TODO -- safe to ignore output audio stream? video_st = icv_add_video_stream_FFMPEG(oc, codec_id, frameSize.width, frameSize.height, frameSize.width*frameSize.height*bitrate_scale, fps, codec_pix_fmt); /* set the output parameters (must be done even if no parameters). */ if (av_set_parameters(oc, NULL) < 0) { CV_ERROR(CV_StsBadArg, "Invalid output format parameters"); } dump_format(oc, 0, filename, 1); /* now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers */ if (!video_st){ CV_ERROR(CV_StsBadArg, "Couldn't open video stream"); } AVCodec *codec; AVCodecContext *c; #if LIBAVFORMAT_BUILD > 4628 c = (video_st->codec); #else c = &(video_st->codec); #endif c->codec_tag = fourcc; /* find the video encoder */ codec = avcodec_find_encoder(c->codec_id); if (!codec) { CV_ERROR(CV_StsBadArg, "codec not found"); } /* open the codec */ if ( (err=avcodec_open(c, codec)) < 0) { char errtext[256]; sprintf(errtext, "Could not open codec '%s': %s", codec->name, icvFFMPEGErrStr(err)); CV_ERROR(CV_StsBadArg, errtext); } outbuf = NULL; if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) { /* allocate output buffer */ /* assume we will never get codec output with more than 4 bytes per pixel... */ outbuf_size = frameSize.width*frameSize.height*4; outbuf = (uint8_t *) av_malloc(outbuf_size); } bool need_color_convert; need_color_convert = (c->pix_fmt != input_pix_fmt); /* allocate the encoded raw picture */ picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert); if (!picture) { CV_ERROR(CV_StsNoMem, "Could not allocate picture"); } /* if the output format is not our input format, then a temporary picture of the input format is needed too. It is then converted to the required output format */ input_picture = NULL; if ( need_color_convert ) { input_picture = icv_alloc_picture_FFMPEG(input_pix_fmt, c->width, c->height, false); if (!input_picture) { CV_ERROR(CV_StsNoMem, "Could not allocate picture"); } } /* open the output file, if needed */ if (!(fmt->flags & AVFMT_NOFILE)) { if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) { CV_ERROR(CV_StsBadArg, "Couldn't open output file for writing"); } } /* write the stream header, if any */ av_write_header( oc ); __END__; return true; }
int VideoFFmpegWriter::execute( boost::uint8_t* in_buffer, int in_width, int in_height, PixelFormat in_pixelFormat ) { _error = IGNORE_FINISH; AVOutputFormat* fmt = 0; fmt = guess_format( _format.c_str(), NULL, NULL ); if( !fmt ) { fmt = guess_format( NULL, filename().c_str(), NULL ); if( !fmt ) { std::cerr << "ffmpegWriter: could not deduce output format from file extension." << std::endl; return false; } } if( !_avformatOptions ) _avformatOptions = avformat_alloc_context(); _avformatOptions->oformat = fmt; snprintf( _avformatOptions->filename, sizeof( _avformatOptions->filename ), "%s", filename().c_str() ); if( !_stream ) { _stream = av_new_stream( _avformatOptions, 0 ); if( !_stream ) { std::cout << "ffmpegWriter: out of memory." << std::endl; return false; } CodecID codecId = fmt->video_codec; AVCodec* userCodec = avcodec_find_encoder_by_name( _codec.c_str() ); if( userCodec ) codecId = userCodec->id; _stream->codec->codec_id = codecId; _stream->codec->codec_type = CODEC_TYPE_VIDEO; _stream->codec->bit_rate = _bitRate; _stream->codec->bit_rate_tolerance = _bitRateTolerance; _stream->codec->width = width(); _stream->codec->height = height(); _stream->codec->time_base = av_d2q( 1.0 / _fps, 100 ); _stream->codec->gop_size = _gopSize; if( _bFrames ) { _stream->codec->max_b_frames = _bFrames; _stream->codec->b_frame_strategy = 0; _stream->codec->b_quant_factor = 2.0; } _stream->codec->mb_decision = _mbDecision; _stream->codec->pix_fmt = _out_pixelFormat; if( !strcmp( _avformatOptions->oformat->name, "mp4" ) || !strcmp( _avformatOptions->oformat->name, "mov" ) || !strcmp( _avformatOptions->oformat->name, "3gp" ) || !strcmp( _avformatOptions->oformat->name, "flv" ) ) _stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; if( av_set_parameters( _avformatOptions, NULL ) < 0 ) { std::cout << "ffmpegWriter: unable to set parameters." << std::endl; freeFormat(); return false; } dump_format( _avformatOptions, 0, filename().c_str(), 1 ); AVCodec* videoCodec = avcodec_find_encoder( codecId ); if( !videoCodec ) { std::cout << "ffmpegWriter: unable to find codec." << std::endl; freeFormat(); return false; } if( avcodec_open( _stream->codec, videoCodec ) < 0 ) { std::cout << "ffmpegWriter: unable to open codec." << std::endl; freeFormat(); return false; } if( !( fmt->flags & AVFMT_NOFILE ) ) { if( url_fopen( &_avformatOptions->pb, filename().c_str(), URL_WRONLY ) < 0 ) { std::cout << "ffmpegWriter: unable to open file." << std::endl; return false; } } av_write_header( _avformatOptions ); } _error = CLEANUP; AVFrame* in_frame = avcodec_alloc_frame(); avcodec_get_frame_defaults( in_frame ); avpicture_fill( (AVPicture*)in_frame, in_buffer, in_pixelFormat, in_width, in_height ); AVFrame* out_frame = avcodec_alloc_frame(); avcodec_get_frame_defaults( out_frame ); int out_picSize = avpicture_get_size( _out_pixelFormat, width(), height() ); boost::uint8_t* out_buffer = (boost::uint8_t*) av_malloc( out_picSize ); avpicture_fill( (AVPicture*) out_frame, out_buffer, _out_pixelFormat, width(), height() ); _sws_context = sws_getCachedContext( _sws_context, in_width, in_height, in_pixelFormat, width(), height(), _out_pixelFormat, SWS_BICUBIC, NULL, NULL, NULL ); std::cout << "ffmpegWriter: input format: " << pixelFormat_toString( in_pixelFormat ) << std::endl; std::cout << "ffmpegWriter: output format: " << pixelFormat_toString( _out_pixelFormat ) << std::endl; if( !_sws_context ) { std::cout << "ffmpeg-conversion failed (" << in_pixelFormat << "->" << _out_pixelFormat << ")." << std::endl; return false; } int error = sws_scale( _sws_context, in_frame->data, in_frame->linesize, 0, height(), out_frame->data, out_frame->linesize ); if( error < 0 ) { std::cout << "ffmpeg-conversion failed (" << in_pixelFormat << "->" << _out_pixelFormat << ")." << std::endl; return false; } int ret = 0; if( ( _avformatOptions->oformat->flags & AVFMT_RAWPICTURE ) != 0 ) { AVPacket pkt; av_init_packet( &pkt ); pkt.flags |= PKT_FLAG_KEY; pkt.stream_index = _stream->index; pkt.data = (boost::uint8_t*) out_frame; pkt.size = sizeof( AVPicture ); ret = av_interleaved_write_frame( _avformatOptions, &pkt ); } else { boost::uint8_t* out_buffer = (boost::uint8_t*) av_malloc( out_picSize ); ret = avcodec_encode_video( _stream->codec, out_buffer, out_picSize, out_frame ); if( ret > 0 ) { AVPacket pkt; av_init_packet( &pkt ); if( _stream->codec->coded_frame && _stream->codec->coded_frame->pts != static_cast<boost::int64_t>( AV_NOPTS_VALUE ) ) // static_cast<unsigned long> ( pkt.pts = av_rescale_q( _stream->codec->coded_frame->pts, _stream->codec->time_base, _stream->time_base ); if( _stream->codec->coded_frame && _stream->codec->coded_frame->key_frame ) pkt.flags |= PKT_FLAG_KEY; pkt.stream_index = _stream->index; pkt.data = out_buffer; pkt.size = ret; ret = av_interleaved_write_frame( _avformatOptions, &pkt ); } av_free( out_buffer ); } av_free( out_buffer ); av_free( out_frame ); av_free( in_frame ); // in_buffer not free (function parameter) if( ret ) { std::cout << "ffmpegWriter: error writing frame to file." << std::endl; return false; } _error = SUCCESS; return true; }
/** * get_oformat * Obtains the output format used for the specified codec. For mpeg4 codecs, * the format is avi; for mpeg1 codec, the format is mpeg. The filename has * to be passed, because it gets the appropriate extension appended onto it. * * Returns * AVOutputFormat pointer or NULL if any error happens. */ static AVOutputFormat *get_oformat(const char *codec, char *filename) { const char *ext; AVOutputFormat *of = NULL; /* * Here, we use guess_format to automatically setup the codec information. * If we are using msmpeg4, manually set that codec here. * We also dynamically add the file extension to the filename here. This was * done to support both mpeg1 and mpeg4 codecs since they have different extensions. */ if ((strcmp(codec, TIMELAPSE_CODEC) == 0) #ifndef FFMPEG_NO_NONSTD_MPEG1 || (strcmp(codec, "mpeg1") == 0) #endif ) { ext = ".mpg"; /* * We use "mpeg1video" for raw mpeg1 format. Using "mpeg" would * result in a muxed output file, which isn't appropriate here. */ #ifdef GUESS_NO_DEPRECATED of = guess_format("mpeg1video", NULL, NULL); #else of = av_guess_format("mpeg1video", NULL, NULL); #endif /* But we want the trailer to be correctly written. */ if (of) of->write_trailer = mpeg1_write_trailer; #ifdef FFMPEG_NO_NONSTD_MPEG1 } else if (strcmp(codec, "mpeg1") == 0) { MOTION_LOG(WRN, TYPE_ENCODER, NO_ERRNO, "%s: *** mpeg1 support for normal" " videos has been disabled ***"); return NULL; #endif } else if (strcmp(codec, "mpeg4") == 0) { ext = ".avi"; #ifdef GUESS_NO_DEPRECATED of = guess_format("mpeg1video", NULL, NULL); #else of = av_guess_format("avi", NULL, NULL); #endif } else if (strcmp(codec, "msmpeg4") == 0) { ext = ".avi"; #ifdef GUESS_NO_DEPRECATED of = guess_format("mpeg1video", NULL, NULL); #else of = av_guess_format("avi", NULL, NULL); #endif /* Manually override the codec id. */ if (of) of->video_codec = AV_CODEC_ID_MSMPEG4V2; } else if (strcmp(codec, "swf") == 0) { ext = ".swf"; #ifdef GUESS_NO_DEPRECATED of = guess_format("mpeg1video", NULL, NULL); #else of = av_guess_format("swf", NULL, NULL); #endif } else if (strcmp(codec, "flv") == 0) { ext = ".flv"; #ifdef GUESS_NO_DEPRECATED of = guess_format("mpeg1video", NULL, NULL); #else of = av_guess_format("flv", NULL, NULL); #endif of->video_codec = AV_CODEC_ID_FLV1; } else if (strcmp(codec, "ffv1") == 0) { ext = ".avi"; #ifdef GUESS_NO_DEPRECATED of = guess_format("mpeg1video", NULL, NULL); #else of = av_guess_format("avi", NULL, NULL); #endif /* * Use the FFMPEG Lossless Video codec (experimental!). * Requires strict_std_compliance to be <= -2 */ if (of) of->video_codec = AV_CODEC_ID_FFV1; } else if (strcmp(codec, "mov") == 0) { ext = ".mov"; #ifdef GUESS_NO_DEPRECATED of = guess_format("mpeg1video", NULL, NULL); #else of = av_guess_format("mov", NULL, NULL); #endif } else if (strcmp (codec, "ogg") == 0) { ext = ".ogg"; #ifdef GUESS_NO_DEPRECATED of = guess_format ("ogg", NULL, NULL); #else of = av_guess_format ("ogg", NULL, NULL); #endif } else { MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: ffmpeg_video_codec option value" " %s is not supported", codec); return NULL; } if (!of) { MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Could not guess format for %s", codec); return NULL; } /* The 4 allows for ".avi" or ".mpg" to be appended. */ strncat(filename, ext, 4); return of; }
AVOutputFormat *AviExporter::getOutputFormat() const { return guess_format("avi", NULL, NULL); }
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; }
int main( int ac, char** av ) { try { comma::command_line_options options( ac, av ); if( options.exists( "--help,-h" ) ) { usage(); } verbose = options.exists( "--verbose,-v" ); bool is_or = options.exists( "--or" ); csv = comma::csv::options( options ); fields = comma::split( csv.fields, ',' ); if( fields.size() == 1 && fields[0].empty() ) { fields.clear(); } std::vector< std::string > unnamed = options.unnamed( "--first-matching,--or,--sorted,--input-sorted,--not-matching,--output-all,--all,--strict,--verbose,-v", "-.*" ); //for( unsigned int i = 0; i < unnamed.size(); constraints_map.insert( std::make_pair( comma::split( unnamed[i], ';' )[0], unnamed[i] ) ), ++i ); bool strict = options.exists( "--strict" ); bool first_matching = options.exists( "--first-matching" ); bool not_matching = options.exists( "--not-matching" ); bool all = options.exists( "--output-all,--all" ); for( unsigned int i = 0; i < unnamed.size(); ++i ) { std::string field = comma::split( unnamed[i], ';' )[0]; bool found = false; for( unsigned int j = 0; j < fields.size() && !found; found = field == fields[j], ++j ); if( !found ) { if( strict ) { std::cerr << "csv-select: on constraint: \"" << unnamed[i] << "\" field \"" << field << "\" not found in fields: " << csv.fields << std::endl; return 1; } std::cerr << "csv-select: warning: on constraint: \"" << unnamed[i] << "\" field \"" << field << "\" not found in fields: " << csv.fields << std::endl; continue; } constraints_map.insert( std::make_pair( field, unnamed[i] ) ); } comma::signal_flag is_shutdown; if( csv.binary() ) { #ifdef WIN32 _setmode( _fileno( stdout ), _O_BINARY ); #endif init_input( csv.format(), options ); comma::csv::binary_input_stream< input_t > istream( std::cin, csv, input ); while( !is_shutdown && ( istream.ready() || ( std::cin.good() && !std::cin.eof() ) ) ) { const input_t* p = istream.read(); if( !p || p->done( is_or ) ) { break; } char match = ( p->is_a_match( is_or ) == !not_matching ) ? 1 : 0; if( match || all ) { std::cout.write( istream.last(), csv.format().size() ); if( all ) { std::cout.write( &match, 1 ); } if( csv.flush ) { std::cout.flush(); } if( first_matching ) { break; } } } } else { std::string line; while( !is_shutdown && std::cin.good() && !std::cin.eof() ) { std::getline( std::cin, line ); line = comma::strip( line, '\r' ); // windows, sigh... if( !line.empty() ) { break; } } if( line.empty() ) { return 0; } comma::csv::format format = options.exists( "--format" ) ? comma::csv::format( options.value< std::string >( "--format" ) ) : guess_format( line ); init_input( format, options ); comma::csv::ascii_input_stream< input_t > istream( std::cin, csv, input ); // todo: quick and dirty: no time to debug why the commented section does not work (but that's the right way) std::istringstream iss( line ); comma::csv::ascii_input_stream< input_t > isstream( iss, csv, input ); const input_t* p = isstream.read(); if( !p || p->done( is_or ) ) { return 0; } bool match = p->is_a_match( is_or ) == !not_matching; if( match || all ) { std::cout << line; if( all ) { std::cout << csv.delimiter << match; } std::cout << std::endl; if( first_matching ) { return 0; } } while( !is_shutdown && ( istream.ready() || ( std::cin.good() && !std::cin.eof() ) ) ) { const input_t* p = istream.read(); if( !p || p->done( is_or ) ) { break; } bool match = p->is_a_match( is_or ) == !not_matching; if( match || all ) { std::cout << comma::join( istream.last(), csv.delimiter ); if( all ) { std::cout << csv.delimiter << match; } std::cout << std::endl; if( first_matching ) { return 0; } } } } return 0; } catch( std::exception& ex ) { std::cerr << "csv-select: caught: " << ex.what() << std::endl; } catch( ... ) { std::cerr << "csv-select: unknown exception" << std::endl; } return 1; }
static int artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int format, struct evbuffer *evbuf) { uint8_t *buf; uint8_t *outbuf; AVCodecContext *src; AVFormatContext *dst_ctx; AVCodecContext *dst; AVOutputFormat *dst_fmt; AVStream *dst_st; AVCodec *img_decoder; AVCodec *img_encoder; int64_t pix_fmt_mask; const enum PixelFormat *pix_fmts; AVFrame *i_frame; AVFrame *o_frame; struct SwsContext *swsctx; AVPacket pkt; int have_frame; int outbuf_len; int ret; src = src_ctx->streams[s]->codec; img_decoder = avcodec_find_decoder(src->codec_id); if (!img_decoder) { DPRINTF(E_LOG, L_ART, "No suitable decoder found for artwork %s\n", src_ctx->filename); return -1; } #if LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 6) ret = avcodec_open2(src, img_decoder, NULL); #else ret = avcodec_open(src, img_decoder); #endif if (ret < 0) { DPRINTF(E_LOG, L_ART, "Could not open codec for decoding: %s\n", strerror(AVUNERROR(ret))); return -1; } /* Set up output */ #if LIBAVFORMAT_VERSION_MAJOR >= 53 || (LIBAVFORMAT_VERSION_MAJOR == 52 && LIBAVFORMAT_VERSION_MINOR >= 45) /* FFmpeg 0.6 */ dst_fmt = av_guess_format("image2", NULL, NULL); #else dst_fmt = guess_format("image2", NULL, NULL); #endif if (!dst_fmt) { DPRINTF(E_LOG, L_ART, "ffmpeg image2 muxer not available\n"); ret = -1; goto out_close_src; } dst_fmt->video_codec = CODEC_ID_NONE; /* Try to keep same codec if possible */ if ((src->codec_id == CODEC_ID_PNG) && (format & ART_CAN_PNG)) dst_fmt->video_codec = CODEC_ID_PNG; else if ((src->codec_id == CODEC_ID_MJPEG) && (format & ART_CAN_JPEG)) dst_fmt->video_codec = CODEC_ID_MJPEG; /* If not possible, select new codec */ if (dst_fmt->video_codec == CODEC_ID_NONE) { if (format & ART_CAN_PNG) dst_fmt->video_codec = CODEC_ID_PNG; else if (format & ART_CAN_JPEG) dst_fmt->video_codec = CODEC_ID_MJPEG; } img_encoder = avcodec_find_encoder(dst_fmt->video_codec); if (!img_encoder) { DPRINTF(E_LOG, L_ART, "No suitable encoder found for codec ID %d\n", dst_fmt->video_codec); ret = -1; goto out_close_src; } dst_ctx = avformat_alloc_context(); if (!dst_ctx) { DPRINTF(E_LOG, L_ART, "Out of memory for format context\n"); ret = -1; goto out_close_src; } dst_ctx->oformat = dst_fmt; #if LIBAVFORMAT_VERSION_MAJOR >= 53 dst_fmt->flags &= ~AVFMT_NOFILE; #else ret = snprintf(dst_ctx->filename, sizeof(dst_ctx->filename), "evbuffer:%p", evbuf); if ((ret < 0) || (ret >= sizeof(dst_ctx->filename))) { DPRINTF(E_LOG, L_ART, "Output artwork URL too long\n"); ret = -1; goto out_free_dst_ctx; } #endif #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 21) dst_st = avformat_new_stream(dst_ctx, NULL); #else dst_st = av_new_stream(dst_ctx, 0); #endif if (!dst_st) { DPRINTF(E_LOG, L_ART, "Out of memory for new output stream\n"); ret = -1; goto out_free_dst_ctx; } dst = dst_st->codec; #if LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 35) avcodec_get_context_defaults3(dst, NULL); #else avcodec_get_context_defaults2(dst, AVMEDIA_TYPE_VIDEO); #endif if (dst_fmt->flags & AVFMT_GLOBALHEADER) dst->flags |= CODEC_FLAG_GLOBAL_HEADER; dst->codec_id = dst_fmt->video_codec; #if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 64) dst->codec_type = AVMEDIA_TYPE_VIDEO; #else dst->codec_type = CODEC_TYPE_VIDEO; #endif pix_fmt_mask = 0; pix_fmts = img_encoder->pix_fmts; while (pix_fmts && (*pix_fmts != -1)) { pix_fmt_mask |= (1 << *pix_fmts); pix_fmts++; } dst->pix_fmt = avcodec_find_best_pix_fmt(pix_fmt_mask, src->pix_fmt, 1, NULL); if (dst->pix_fmt < 0) { DPRINTF(E_LOG, L_ART, "Could not determine best pixel format\n"); ret = -1; goto out_free_dst_ctx; } DPRINTF(E_DBG, L_ART, "Selected pixel format: %d\n", dst->pix_fmt); dst->time_base.num = 1; dst->time_base.den = 25; dst->width = out_w; dst->height = out_h; #if LIBAVFORMAT_VERSION_MAJOR <= 52 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR <= 1) ret = av_set_parameters(dst_ctx, NULL); if (ret < 0) { DPRINTF(E_LOG, L_ART, "Invalid parameters for artwork output: %s\n", strerror(AVUNERROR(ret))); ret = -1; goto out_free_dst_ctx; } #endif /* Open encoder */ #if LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 6) ret = avcodec_open2(dst, img_encoder, NULL); #else ret = avcodec_open(dst, img_encoder); #endif if (ret < 0) { DPRINTF(E_LOG, L_ART, "Could not open codec for encoding: %s\n", strerror(AVUNERROR(ret))); ret = -1; goto out_free_dst_ctx; } i_frame = avcodec_alloc_frame(); o_frame = avcodec_alloc_frame(); if (!i_frame || !o_frame) { DPRINTF(E_LOG, L_ART, "Could not allocate input/output frame\n"); ret = -1; goto out_free_frames; } ret = avpicture_get_size(dst->pix_fmt, src->width, src->height); DPRINTF(E_DBG, L_ART, "Artwork buffer size: %d\n", ret); buf = (uint8_t *)av_malloc(ret); if (!buf) { DPRINTF(E_LOG, L_ART, "Out of memory for artwork buffer\n"); ret = -1; goto out_free_frames; } avpicture_fill((AVPicture *)o_frame, buf, dst->pix_fmt, src->width, src->height); swsctx = sws_getContext(src->width, src->height, src->pix_fmt, dst->width, dst->height, dst->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL); if (!swsctx) { DPRINTF(E_LOG, L_ART, "Could not get SWS context\n"); ret = -1; goto out_free_buf; } /* Get frame */ have_frame = 0; while (av_read_frame(src_ctx, &pkt) == 0) { if (pkt.stream_index != s) { av_free_packet(&pkt); continue; } #if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 32) /* FFmpeg 0.6 */ avcodec_decode_video2(src, i_frame, &have_frame, &pkt); #else avcodec_decode_video(src, i_frame, &have_frame, pkt.data, pkt.size); #endif break; } if (!have_frame) { DPRINTF(E_LOG, L_ART, "Could not decode artwork\n"); av_free_packet(&pkt); sws_freeContext(swsctx); ret = -1; goto out_free_buf; } /* Scale */ #if LIBSWSCALE_VERSION_MAJOR >= 1 || (LIBSWSCALE_VERSION_MAJOR == 0 && LIBSWSCALE_VERSION_MINOR >= 9) /* FFmpeg 0.6, libav 0.6+ */ sws_scale(swsctx, (const uint8_t * const *)i_frame->data, i_frame->linesize, 0, src->height, o_frame->data, o_frame->linesize); #else sws_scale(swsctx, i_frame->data, i_frame->linesize, 0, src->height, o_frame->data, o_frame->linesize); #endif sws_freeContext(swsctx); av_free_packet(&pkt); /* Open output file */ #if LIBAVFORMAT_VERSION_MAJOR >= 53 dst_ctx->pb = avio_evbuffer_open(evbuf); #else ret = url_fopen(&dst_ctx->pb, dst_ctx->filename, URL_WRONLY); #endif if (ret < 0) { DPRINTF(E_LOG, L_ART, "Could not open artwork destination buffer\n"); ret = -1; goto out_free_buf; } /* Encode frame */ outbuf_len = dst->width * dst->height * 3; if (outbuf_len < FF_MIN_BUFFER_SIZE) outbuf_len = FF_MIN_BUFFER_SIZE; outbuf = (uint8_t *)av_malloc(outbuf_len); if (!outbuf) { DPRINTF(E_LOG, L_ART, "Out of memory for encoded artwork buffer\n"); #if LIBAVFORMAT_VERSION_MAJOR >= 53 avio_evbuffer_close(dst_ctx->pb); #else url_fclose(dst_ctx->pb); #endif ret = -1; goto out_free_buf; } #if LIBAVCODEC_VERSION_MAJOR >= 54 av_init_packet(&pkt); pkt.data = outbuf; pkt.size = outbuf_len; ret = avcodec_encode_video2(dst, &pkt, o_frame, &have_frame); if (!ret && have_frame && dst->coded_frame) { dst->coded_frame->pts = pkt.pts; dst->coded_frame->key_frame = !!(pkt.flags & AV_PKT_FLAG_KEY); } else if (ret < 0) { DPRINTF(E_LOG, L_ART, "Could not encode artwork\n"); ret = -1; goto out_fclose_dst; } #else ret = avcodec_encode_video(dst, outbuf, outbuf_len, o_frame); if (ret <= 0) { DPRINTF(E_LOG, L_ART, "Could not encode artwork\n"); ret = -1; goto out_fclose_dst; } av_init_packet(&pkt); pkt.stream_index = 0; pkt.data = outbuf; pkt.size = ret; #endif #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 3) ret = avformat_write_header(dst_ctx, NULL); #else ret = av_write_header(dst_ctx); #endif if (ret != 0) { DPRINTF(E_LOG, L_ART, "Could not write artwork header: %s\n", strerror(AVUNERROR(ret))); ret = -1; goto out_fclose_dst; } ret = av_interleaved_write_frame(dst_ctx, &pkt); if (ret != 0) { DPRINTF(E_LOG, L_ART, "Error writing artwork\n"); ret = -1; goto out_fclose_dst; } ret = av_write_trailer(dst_ctx); if (ret != 0) { DPRINTF(E_LOG, L_ART, "Could not write artwork trailer: %s\n", strerror(AVUNERROR(ret))); ret = -1; goto out_fclose_dst; } switch (dst_fmt->video_codec) { case CODEC_ID_PNG: ret = ART_FMT_PNG; break; case CODEC_ID_MJPEG: ret = ART_FMT_JPEG; break; default: DPRINTF(E_LOG, L_ART, "Unhandled rescale output format\n"); ret = -1; break; } out_fclose_dst: #if LIBAVFORMAT_VERSION_MAJOR >= 53 avio_evbuffer_close(dst_ctx->pb); #else url_fclose(dst_ctx->pb); #endif av_free(outbuf); out_free_buf: av_free(buf); out_free_frames: if (i_frame) av_free(i_frame); if (o_frame) av_free(o_frame); avcodec_close(dst); out_free_dst_ctx: avformat_free_context(dst_ctx); out_close_src: avcodec_close(src); return ret; }
//---------------------------------------------------------------- // main_utf8 // int main_utf8(int argc, char **argv) { const char *input = NULL; const char *output_prefix = ""; double target_segment_duration = 0.0; char *segment_duration_check = NULL; const char *playlist_filename = NULL; const char *http_prefix = ""; long max_tsfiles = 0; char *max_tsfiles_check = NULL; double prev_segment_time = 0.0; double segment_duration = 0.0; unsigned int output_index = 1; const AVClass *fc = avformat_get_class(); AVDictionary *format_opts = NULL; AVOutputFormat *ofmt = NULL; AVFormatContext *ic = NULL; AVFormatContext *oc = NULL; AVStream *video_st = NULL; AVStream *audio_st = NULL; AVCodec *codec = NULL; char *output_filename = NULL; int if_save_keyframe = 0; //add by wanggm char *keyframeinfo_filename = NULL; //add by wanggm json_object *obj = NULL; //add by wanggm json_object *info_arr_obj = NULL; //add by wanggm int if_monitor_related_process = 0; //add by wanggm pid_t relatedProcessPid = 1; //add by wanggm char *pid_filename = NULL; int video_index = -1; int audio_index = -1; int kill_file = 0; int decode_done = 0; int ret = 0; int i = 0; TSMStreamLace * streamLace = NULL; TSMPlaylist * playlist = NULL; const double segment_duration_error_tolerance = 0.05; double extra_duration_needed = 0; int strict_segment_duration = 0; av_log_set_level(AV_LOG_INFO); for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-i") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -i parameter"); i++; input = argv[i]; } else if (strcmp(argv[i], "-o") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -o parameter"); i++; output_prefix = argv[i]; } else if (strcmp(argv[i], "-d") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -d parameter"); i++; target_segment_duration = strtod(argv[i], &segment_duration_check); if (segment_duration_check == argv[i] || target_segment_duration == HUGE_VAL || target_segment_duration == -HUGE_VAL){ usage3(argv, "invalid segment duration: ", argv[i]); } } else if (strcmp(argv[i], "-x") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -x parameter"); i++; playlist_filename = argv[i]; } else if (strcmp(argv[i], "-p") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -p parameter"); i++; http_prefix = argv[i]; } else if (strcmp(argv[i], "-w") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -w parameter"); i++; max_tsfiles = strtol(argv[i], &max_tsfiles_check, 10); if (max_tsfiles_check == argv[i] || max_tsfiles < 0 || max_tsfiles >= INT_MAX) { usage3(argv, "invalid live stream max window size: ", argv[i]); } } else if (strcmp(argv[i], "-P") == 0) { if ((argc - i) <= 1) usage(argv, "could not parse -P parameter"); i++; pid_filename = argv[i]; } else if (strcmp(argv[i], "--watch-for-kill-file") == 0) { // end program when it finds a file with name 'kill': kill_file = 1; } else if (strcmp(argv[i], "--strict-segment-duration") == 0) { // force segment creation on non-keyframe boundaries: strict_segment_duration = 1; } else if (strcmp(argv[i], "--avformat-option") == 0) { const AVOption *of; const char *opt; const char *arg; if ((argc - i) <= 1) usage(argv, "could not parse --avformat-option parameter"); i++; opt = argv[i]; if ((argc - i) <= 1) usage(argv, "could not parse --avformat-option parameter"); i++; arg = argv[i]; if ((of = av_opt_find(&fc, opt, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) av_dict_set(&format_opts, opt, arg, (of->type == AV_OPT_TYPE_FLAGS) ? AV_DICT_APPEND : 0); else usage3(argv, "unknown --avformat-option parameter: ", opt); } else if (strcmp(argv[i], "--loglevel") == 0) { const char *arg; if ((argc - i) <= 1) usage(argv, "could not parse --loglevel parameter"); i++; arg = argv[i]; if (loglevel(arg)) usage3(argv, "unknown --loglevel parameter: ", arg); } else if (strcmp(argv[i], "-k") == 0) { //add by wanggm for save key frame information into json file. if ((argc - i) <= 1) usage(argv, "could not parse -k parameter"); i++; if_save_keyframe = atoi(argv[i]); } else if( strcmp(argv[i], "-s") == 0) {//add by wanggm for set the start index of ts file. if ( (argc -i ) <= 1) usage(argv, "could not parse -s parmeter"); i++; char *output_index_check = NULL; output_index = strtol(argv[i], &output_index_check, 10); if ( output_index_check== argv[i] || output_index < 0 || output_index >= INT_MAX) { usage3(argv, "invalid start index of ts file: ", argv[i]); } } else if( strcmp(argv[i], "-m") == 0) { // add by wanggm for exit by monitor the process of which pid is given. if ((argc - i) <= 1) usage(argv, "could not parse -m parmeter"); i++; if_monitor_related_process = 1; unsigned int tmpPid= atoi(argv[i]); if( tmpPid > 0) { relatedProcessPid = (pid_t) tmpPid; fprintf(stdout, "%s I will exit when the process PID= %d exit.\n", getSystemTime(timeChar), relatedProcessPid); } } } if (!input) { usage(argv, "-i input file parameter must be specified"); } if (!playlist_filename) { usage(argv, "-x m3u8 playlist file parameter must be specified"); } if (target_segment_duration == 0.0) { usage(argv, "-d segment duration parameter must be specified"); } if( output_index <= 0 ) { output_index = 1; } if( 1 == if_monitor_related_process) { pthread_t id; pthread_create(&id, NULL, (void*)monitor_process, relatedProcessPid); } // Create PID file if (pid_filename) { FILE* pid_file = fopen_utf8(pid_filename, "wb"); if (pid_file) { fprintf(pid_file, "%d", getpid()); fclose(pid_file); } } av_register_all(); avformat_network_init(); if (!strcmp(input, "-")) { input = "pipe:"; } output_filename = (char*) malloc( sizeof(char) * (strlen(output_prefix) + 15)); //add by wanggm if( if_save_keyframe == 1) { keyframeinfo_filename = (char*) malloc( sizeof(char)* (strlen(output_prefix) + 15)); } if (!output_filename || (1 == if_save_keyframe && !keyframeinfo_filename)) { fprintf(stderr, "%s Could not allocate space for output filenames\n", getSystemTime( timeChar)); goto error; } playlist = createPlaylist(max_tsfiles, target_segment_duration, http_prefix); if (!playlist) { fprintf(stderr, "%s Could not allocate space for m3u8 playlist structure\n", getSystemTime( timeChar)); goto error; } ret = avformat_open_input(&ic, input, NULL, (format_opts) ? &format_opts : NULL); if (ret != 0) { fprintf(stderr, "%sCould not open input file, make sure it is an mpegts or mp4 file: %d\n", getSystemTime(timeChar), ret); goto error; } av_dict_free(&format_opts); if (avformat_find_stream_info(ic, NULL) < 0) { fprintf(stderr, "%s Could not read stream information\n", getSystemTime( timeChar)); goto error; } #if LIBAVFORMAT_VERSION_MAJOR > 52 || (LIBAVFORMAT_VERSION_MAJOR == 52 && \ LIBAVFORMAT_VERSION_MINOR >= 45) ofmt = av_guess_format("mpegts", NULL, NULL); #else ofmt = guess_format("mpegts", NULL, NULL); #endif if (!ofmt) { fprintf(stderr, "%s Could not find MPEG-TS muxer\n", getSystemTime( timeChar)); goto error; } oc = avformat_alloc_context(); if (!oc) { fprintf(stderr, "%s Could not allocated output context\n", getSystemTime( timeChar)); goto error; } oc->oformat = ofmt; video_index = -1; audio_index = -1; for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) { switch (ic->streams[i]->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: video_index = i; ic->streams[i]->discard = AVDISCARD_NONE; video_st = add_output_stream(oc, ic->streams[i]); break; case AVMEDIA_TYPE_AUDIO: audio_index = i; ic->streams[i]->discard = AVDISCARD_NONE; audio_st = add_output_stream(oc, ic->streams[i]); break; default: ic->streams[i]->discard = AVDISCARD_ALL; break; } } av_dump_format(oc, 0, output_prefix, 1); if (video_index >= 0) { codec = avcodec_find_decoder(video_st->codec->codec_id); if (!codec) { fprintf(stderr, "%s Could not find video decoder, key frames will not be honored\n", getSystemTime( timeChar)); } if (avcodec_open2(video_st->codec, codec, NULL) < 0) { fprintf(stderr, "%s Could not open video decoder, key frames will not be honored\n", getSystemTime( timeChar)); } } snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, output_index); if( 1 == if_save_keyframe) { snprintf(keyframeinfo_filename, strlen(output_prefix) + 15, "%s-%u.idx", output_prefix, output_index); obj = json_object_new_object(); info_arr_obj = create_json_header(obj); } if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "%s Could not open '%s'\n", getSystemTime( timeChar),output_filename); goto error; } if (avformat_write_header(oc, NULL)) { fprintf(stderr, "%s Could not write mpegts header to first output file\n", getSystemTime( timeChar)); goto error; } prev_segment_time = (double) (ic->start_time) / (double) (AV_TIME_BASE); streamLace = createStreamLace(ic->nb_streams); // add by houmr int continue_error_cnt = 0; //int pushcnt = 0; //int popcnt = 0; int tscnt = 0; int audiopktcnt = 0; int videopktcnt = 0; int kfcnt = 0; int errpktcnt = 0; ///////////////////////// do { double segment_time = 0.0; AVPacket packet; double packetStartTime = 0.0; double packetDuration = 0.0; if (!decode_done) { //fprintf(stdout, "%s av_read_frame() begin.\n", getSystemTime( timeChar)); decode_done = av_read_frame(ic, &packet); //fprintf(stdout, "%s av_read_frame() end. packet.size=%d stream_index=%d duration=%d\n", getSystemTime( timeChar), packet.size, packet.stream_index, packet.duration); //fprintf(stdout, "%s decode_done=%d\n", getSystemTime( timeChar),decode_done); if (!decode_done) { if (packet.stream_index != video_index && packet.stream_index != audio_index) { if( ++errpktcnt >= 10) { decode_done = 1; } fprintf(stderr, "%s packet is not video or audio, packet.stream_index=%d\n", getSystemTime( timeChar), packet.stream_index); av_free_packet(&packet); continue; } errpktcnt = 0; /*printf("orgin : index - %d\t pts = %s\t duration=%d\n", packet.stream_index, av_ts2str(packet.pts), packet.duration);*/ // add by houmr /*if (adjust_pts(&packet, video_index, audio_index) < 0) { av_free_packet(&packet); continue; } */ ///////////////////////////////////// double timeStamp = (double) (packet.pts) * (double) (ic->streams[packet.stream_index]->time_base.num) / (double) (ic->streams[packet.stream_index]->time_base.den); if (av_dup_packet(&packet) < 0) { fprintf(stderr, "%s Could not duplicate packet\n" ,getSystemTime( timeChar)); av_free_packet(&packet); break; } /* for(int i = 0; i < streamLace->numStreams; ++i) { fprintf(stdout, "streamLace[%d].size=%d\t", i, streamLace->streams[i]->size); } fprintf(stdout, "\n"); */ insertPacket(streamLace, &packet, timeStamp); } } if (countPackets(streamLace) < 50 && !decode_done) { /* allow the queue to fill up so that the packets can be sorted properly */ continue; } if (!removePacket(streamLace, &packet)) { fprintf(stdout, "%s get packet failed!!\n", getSystemTime( timeChar)); if (decode_done) { /* the queue is empty, we are done */ break; } assert(decode_done); continue; } //fprintf(stdout, "%s get 1 packet success. packet info: pts=%ld, dts=%ld\n", getSystemTime( timeChar), packet.pts, packet.dts); packetStartTime = (double) (packet.pts) * (double) (ic->streams[packet.stream_index]->time_base.num) / (double) (ic->streams[packet.stream_index]->time_base.den); packetDuration = (double) (packet.duration) * (double) (ic->streams[packet.stream_index]->time_base.num) / (double) (ic->streams[packet.stream_index]->time_base.den); #if !defined(NDEBUG) && (defined(DEBUG) || defined(_DEBUG)) if (av_log_get_level() >= AV_LOG_VERBOSE) fprintf(stderr, "%s stream %i, packet [%f, %f)\n", getSystemTime( timeChar), packet.stream_index, packetStartTime, packetStartTime + packetDuration); #endif segment_duration = packetStartTime + packetDuration - prev_segment_time; // NOTE: segments are supposed to start on a keyframe. // If the keyframe interval and segment duration do not match // forcing the segment creation for "better seeking behavior" // will result in decoding artifacts after seeking or stream switching. if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY || strict_segment_duration)) { //This is video packet and ( packet is key frame or strict time is needed ) segment_time = packetStartTime; } else if (video_index < 0) { //This stream doesn't contain video stream segment_time = packetStartTime; } else { //This is a video packet or a video packet but not key frame segment_time = prev_segment_time; } //fprintf(stdout, "%s extra_duration_needed=%f\n", getSystemTime( timeChar), extra_duration_needed); if (segment_time - prev_segment_time + segment_duration_error_tolerance > target_segment_duration + extra_duration_needed) { fprintf(stdout, "%s segment_time=%lf prev_segment_time=%lf > target_segment_duration=%lf extra_duration_needed=%lf\n", getSystemTime( timeChar), segment_time, prev_segment_time, target_segment_duration, extra_duration_needed); fprintf(stdout, "%s File %s contains %d PES packet, of which %d are audio packet, %d are video packet within %d key frame.\n", getSystemTime( timeChar), output_filename, tscnt, audiopktcnt, videopktcnt, kfcnt); fflush(stdout); /* for(int i = 0; i < streamLace->numStreams; ++i) { fprintf(stdout, "%s streamLace[%d].size=%d\t", getSystemTime( timeChar), i, streamLace->streams[i]->size); } */ tscnt = audiopktcnt = videopktcnt = kfcnt = 0; avio_flush(oc->pb); avio_close(oc->pb); // Keep track of accumulated rounding error to account for it in later chunks. /* double segment_duration = segment_time - prev_segment_time; int rounded_segment_duration = (int) (segment_duration + 0.5); extra_duration_needed += (double) rounded_segment_duration - segment_duration; */ double seg_dur = segment_time - prev_segment_time; int rounded_segment_duration = (int) (seg_dur + 0.5); extra_duration_needed += (target_segment_duration - seg_dur - segment_duration_error_tolerance); //fprintf(stdout, "%s ________extra_duration_needed = %lf\n", getSystemTime( timeChar), extra_duration_needed); updatePlaylist(playlist, playlist_filename, output_filename, output_index, rounded_segment_duration); snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, ++output_index); //add by wanggm //Save the all the keyframe information into json file if( 1 == if_save_keyframe && NULL != obj) { save_json_to_file(keyframeinfo_filename, obj); obj = info_arr_obj = NULL; snprintf(keyframeinfo_filename, strlen(output_prefix) + 15, "%s-%u.idx", output_prefix, output_index); } if (avio_open(&oc->pb, output_filename, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "%s Could not open '%s'\n", getSystemTime( timeChar), output_filename); break; } // close when we find the 'kill' file if (kill_file) { FILE* fp = fopen("kill", "rb"); if (fp) { fprintf(stderr, "%s user abort: found kill file\n", getSystemTime( timeChar)); fclose(fp); remove("kill"); decode_done = 1; removeAllPackets(streamLace); } } prev_segment_time = segment_time; } //add by wanggm. ++tscnt; if( video_index == packet.stream_index) { ++videopktcnt; if(1 == packet.flags) { ++kfcnt; if( 1 == if_save_keyframe) { //If it is key frame, it's information should be saved. //fprintf(stdout, "%s packet is keyframe, packet.pts=%ld\n", getSystemTime( timeChar), packet.pts); snprintf(keyframeinfo_filename, strlen(output_prefix) + 15, "%s-%u.idx", output_prefix, output_index); if (NULL == obj && NULL == info_arr_obj) { obj = json_object_new_object(); info_arr_obj = create_json_header(obj); } avio_flush(oc->pb); //flush the previous data into ts file. int64_t offset = avio_tell(oc->pb); //Get the offset of this key frame in the file. save_keyframe_info(info_arr_obj, offset, packet.pts); //fprintf(stdout, "%s Keyframe.pos=%ld \tkeyframe.pts=%ld\n", getSystemTime( timeChar), offset, (long)packet.pts); } } }else if( audio_index == packet.stream_index) { ++audiopktcnt; } //fprintf(stdout, "%s packet is not keyframe.\n", getSystemTime( timeChar)); ret = av_interleaved_write_frame(oc, &packet); if (ret < 0) { fprintf(stderr, "%s Warning: Could not write frame of stream\n", getSystemTime( timeChar)); // add by houmr continue_error_cnt++; if (continue_error_cnt > 10) { av_free_packet(&packet); break; } } else if (ret > 0) { fprintf(stderr, "%s End of stream requested\n", getSystemTime( timeChar)); av_free_packet(&packet); break; } else { // add by houmr error continue_error_cnt = 0; //////////////////////// } av_free_packet(&packet); } while (!decode_done || countPackets(streamLace) > 0); av_write_trailer(oc); if (video_index >= 0) { avcodec_close(video_st->codec); } for (i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]->codec); av_freep(&oc->streams[i]); } avio_close(oc->pb); av_free(oc); updatePlaylist(playlist, playlist_filename, output_filename, output_index, segment_duration); closePlaylist(playlist); releasePlaylist(&playlist); //add by wanggm if( 1 == if_save_keyframe && obj != NULL) { save_json_to_file(keyframeinfo_filename, obj); } if (pid_filename) { remove(pid_filename); } fflush(stdout); fflush(stderr); return 0; error: if (pid_filename) { remove(pid_filename); } return 1; }