X-Git-Url: http://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.0%2Fcinelerra%2Fffmpeg.C;h=89175ff737032e2bf6790c7676f9f4ec280ebd34;hb=955d712ff475171e99d7910ead049a9342ca8b21;hp=694f18343433d0a4118ac6c3e7f725a7ae157a94;hpb=a191ee43586c4563e15fb3ab4c7594be3e81fa3b;p=goodguy%2Fhistory.git diff --git a/cinelerra-5.0/cinelerra/ffmpeg.C b/cinelerra-5.0/cinelerra/ffmpeg.C index 694f1834..89175ff7 100644 --- a/cinelerra-5.0/cinelerra/ffmpeg.C +++ b/cinelerra-5.0/cinelerra/ffmpeg.C @@ -30,10 +30,16 @@ Mutex FFMPEG::fflock("FFMPEG::fflock"); -static void ff_err(int ret, const char *msg) +static void ff_err(int ret, const char *fmt, ...) { - char errmsg[BCSTRLEN]; av_strerror(ret, errmsg, sizeof(errmsg)); - fprintf(stderr,"%s: %s\n",msg, errmsg); + char msg[BCTEXTLEN]; + va_list ap; + va_start(ap, fmt); + vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + char errmsg[BCSTRLEN]; + av_strerror(ret, errmsg, sizeof(errmsg)); + fprintf(stderr,_("%s err: %s\n"),msg, errmsg); } FFPacket::FFPacket() @@ -321,7 +327,7 @@ int FFStream::read_packet() if( ret >= 0 ) return 1; st_eof(1); if( ret == AVERROR_EOF ) return 0; - fprintf(stderr, "FFStream::read_packet: av_read_frame failed\n"); + ff_err(ret, "FFStream::read_packet: av_read_frame failed\n"); flushed = 1; return -1; } @@ -381,7 +387,7 @@ int FFStream::read_filter(AVFrame *frame) if( ret < 0 ) { if( ret == AVERROR(EAGAIN) ) return 0; if( ret == AVERROR_EOF ) { st_eof(1); return -1; } - fprintf(stderr, "FFStream::read_filter: av_buffersink_get_frame failed\n"); + ff_err(ret, "FFStream::read_filter: av_buffersink_get_frame failed\n"); return ret; } return 1; @@ -403,6 +409,29 @@ int FFStream::read_frame(AVFrame *frame) return ret; } +int FFStream::write_packet(FFPacket &pkt) +{ + bs_filter(pkt); + av_packet_rescale_ts(pkt, st->codec->time_base, st->time_base); + pkt->stream_index = st->index; + return av_interleaved_write_frame(ffmpeg->fmt_ctx, pkt); +} + +int FFStream::flush() +{ + int ret = 0; + while( ret >= 0 ) { + FFPacket pkt; + int got_packet = 0; + ret = encode_frame(pkt, 0, got_packet); + if( ret < 0 || !got_packet ) break; + ret = write_packet(pkt); + } + if( ret < 0 ) + ff_err(ret, "FFStream::flush"); + return ret >= 0 ? 0 : 1; +} + FFAudioStream::FFAudioStream(FFMPEG *ffmpeg, AVStream *strm, int idx) : FFStream(ffmpeg, strm, idx) { @@ -447,7 +476,7 @@ int FFAudioStream::load_history(uint8_t **data, int len) int ret = swr_convert(resample_context, (uint8_t**)&aud_bfr, aud_bfr_sz, (const uint8_t**)data, len); if( ret < 0 ) { - fprintf(stderr, "FFAudioStream::load_history: swr_convert failed\n"); + ff_err(ret, "FFAudioStream::load_history: swr_convert failed\n"); return -1; } samples = aud_bfr; @@ -463,7 +492,7 @@ int FFAudioStream::decode_frame(AVFrame *frame, int &got_frame) { int ret = avcodec_decode_audio4(st->codec, frame, &got_frame, ipkt); if( ret < 0 ) { - fprintf(stderr, "FFAudioStream::decode_frame: Could not read audio frame\n"); + ff_err(ret, "FFAudioStream::decode_frame: Could not read audio frame\n"); return -1; } return ret; @@ -512,7 +541,7 @@ int FFAudioStream::init_frame(AVFrame *frame) frame->sample_rate = ctx->sample_rate; int ret = av_frame_get_buffer(frame, 0); if (ret < 0) - fprintf(stderr, "FFAudioStream::init_frame: av_frame_get_buffer failed\n"); + ff_err(ret, "FFAudioStream::init_frame: av_frame_get_buffer failed\n"); return ret; } @@ -533,7 +562,7 @@ int FFAudioStream::load(int64_t pos, int len) curr_pos += frame->nb_samples; } } - if( flushed && end_pos > curr_pos ) { + if( end_pos > curr_pos ) { zero(end_pos - curr_pos); curr_pos = end_pos; } @@ -577,7 +606,7 @@ int FFAudioStream::encode(double **samples, int len) (uint8_t **)frame->extended_data, frame_sz, (const uint8_t **)&bfrp, frame_sz); if( ret < 0 ) { - fprintf(stderr, "FFAudioStream::encode: swr_convert failed\n"); + ff_err(ret, "FFAudioStream::encode: swr_convert failed\n"); break; } frm->queue(curr_pos); @@ -590,6 +619,16 @@ int FFAudioStream::encode(double **samples, int len) return ret >= 0 ? 0 : 1; } +int FFAudioStream::encode_frame(FFPacket &pkt, AVFrame *frame, int &got_packet) +{ + int ret = avcodec_encode_audio2(st->codec, pkt, frame, &got_packet); + if( ret < 0 ) { + ff_err(ret, "FFAudioStream::encode_frame: encode audio failed\n"); + return -1; + } + return ret; +} + FFVideoStream::FFVideoStream(FFMPEG *ffmpeg, AVStream *strm, int idx) : FFStream(ffmpeg, strm, idx) { @@ -610,7 +649,7 @@ int FFVideoStream::decode_frame(AVFrame *frame, int &got_frame) { int ret = avcodec_decode_video2(st->codec, frame, &got_frame, ipkt); if( ret < 0 ) { - fprintf(stderr, "FFVideoStream::decode_frame: Could not read video frame\n"); + ff_err(ret, "FFVideoStream::decode_frame: Could not read video frame\n"); return -1; } if( got_frame ) @@ -620,12 +659,12 @@ int FFVideoStream::decode_frame(AVFrame *frame, int &got_frame) int FFVideoStream::load(VFrame *vframe, int64_t pos) { - if( video_seek(pos) < 0 ) return -1; + int ret = video_seek(pos); + if( ret < 0 ) return -1; if( !frame && !(frame=av_frame_alloc()) ) { fprintf(stderr, "FFVideoStream::load: av_frame_alloc failed\n"); return -1; } - int ret = 0; for( int i=0; ret>=0 && !flushed && curr_pos<=pos && i<1000; ++i ) { ret = read_frame(frame); } @@ -647,6 +686,7 @@ int FFVideoStream::video_seek(int64_t pos) if( gop < 4 ) gop = 4; if( gop > 64 ) gop = 64; if( pos >= curr_pos && pos <= curr_pos + gop ) return 0; + if( pos == curr_pos-1 && curr_pos > seek_pos ) return 1; if( !st->codec || !st->codec->codec ) return -1; avcodec_flush_buffers(st->codec); // back up a few frames to read up to current to help repair damages @@ -695,6 +735,15 @@ int FFVideoStream::encode(VFrame *vframe) return ret >= 0 ? 0 : 1; } +int FFVideoStream::encode_frame(FFPacket &pkt, AVFrame *frame, int &got_packet) +{ + int ret = avcodec_encode_video2(st->codec, pkt, frame, &got_packet); + if( ret < 0 ) { + ff_err(ret, "FFVideoStream::encode_frame: encode video failed\n"); + return -1; + } + return ret; +} PixelFormat FFVideoStream::color_model_to_pix_fmt(int color_model) { @@ -769,9 +818,10 @@ int FFVideoStream::convert_picture_vframe(VFrame *frame, " sws_getCachedContext() failed\n"); return 1; } - if( sws_scale(convert_ctx, ip->data, ip->linesize, 0, ih, - opic.data, opic.linesize) < 0 ) { - fprintf(stderr, "FFVideoStream::convert_picture_frame: sws_scale() failed\n"); + int ret = sws_scale(convert_ctx, ip->data, ip->linesize, 0, ih, + opic.data, opic.linesize); + if( ret < 0 ) { + ff_err(ret, "FFVideoStream::convert_picture_frame: sws_scale() failed\n"); return 1; } return 0; @@ -832,9 +882,10 @@ int FFVideoStream::convert_vframe_picture(VFrame *frame, " sws_getCachedContext() failed\n"); return 1; } - if( sws_scale(convert_ctx, opic.data, opic.linesize, 0, frame->get_h(), - op->data, op->linesize) < 0 ) { - fprintf(stderr, "FFVideoStream::convert_frame_picture: sws_scale() failed\n"); + int ret = sws_scale(convert_ctx, opic.data, opic.linesize, 0, frame->get_h(), + op->data, op->linesize); + if( ret < 0 ) { + ff_err(ret, "FFVideoStream::convert_frame_picture: sws_scale() failed\n"); return 1; } return 0; @@ -890,8 +941,8 @@ FFMPEG::~FFMPEG() delete flow_lock; delete mux_lock; av_dict_free(&opts); - delete opt_video_filter; - delete opt_audio_filter; + delete [] opt_video_filter; + delete [] opt_audio_filter; } int FFMPEG::check_sample_rate(AVCodec *codec, int sample_rate) @@ -949,8 +1000,6 @@ AVRational FFMPEG::to_time_base(int sample_rate) return (AVRational){1, sample_rate}; } -extern void get_exe_path(char *result); // from main.C - void FFMPEG::set_option_path(char *path, const char *fmt, ...) { get_exe_path(path); @@ -1035,8 +1084,8 @@ int FFMPEG::get_encoder(const char *options, return 1; } if( get_encoder(fp, format, codec, bsfilter, bsargs) ) - eprintf("FFMPEG::get_encoder:" - " err: format/codec not found %s\n", options); + eprintf(_("FFMPEG::get_encoder:" + " err: format/codec not found %s\n"), options); fclose(fp); return 0; } @@ -1066,12 +1115,14 @@ int FFMPEG::read_options(const char *options, AVDictionary *&opts) return ret; } -int FFMPEG::scan_options(const char *options, AVDictionary *&opts) +int FFMPEG::scan_options(const char *options, AVDictionary *&opts, AVStream *st) { FILE *fp = fmemopen((void *)options,strlen(options),"r"); if( !fp ) return 0; int ret = read_options(fp, options, opts); fclose(fp); + AVDictionaryEntry *tag = av_dict_get(opts, "id", NULL, 0); + if( tag ) st->id = strtol(tag->value,0,0); return ret; } @@ -1086,8 +1137,8 @@ int FFMPEG::read_options(FILE *fp, const char *options, AVDictionary *&opts) if( line[0] == '\n' ) continue; char key[BCSTRLEN], val[BCTEXTLEN]; if( scan_option_line(line, key, val) ) { - eprintf("FFMPEG::read_options:" - " err reading %s: line %d\n", options, no); + eprintf(_("FFMPEG::read_options:" + " err reading %s: line %d\n"), options, no); ret = 1; } if( !ret ) { @@ -1166,7 +1217,7 @@ int FFMPEG::info(char *text, int len) for( int i=0; i<(int)fmt_ctx->nb_streams; ++i ) { AVStream *st = fmt_ctx->streams[i]; AVCodecContext *avctx = st->codec; - report("stream %d, id 0x%06x:\n", i, avctx->codec_id); + report(_("stream %d, id 0x%06x:\n"), i, avctx->codec_id); const AVCodecDescriptor *desc = avcodec_descriptor_get(avctx->codec_id); if( avctx->codec_type == AVMEDIA_TYPE_VIDEO ) { AVRational framerate = av_guess_frame_rate(fmt_ctx, st, 0); @@ -1198,7 +1249,7 @@ int FFMPEG::info(char *text, int len) report(" %d:%02d:%05.2f\n", hrs, mins, secs); } else - report(" codec_type unknown\n"); + report(_(" codec_type unknown\n")); } report("\n"); for( int i=0; i<(int)fmt_ctx->nb_programs; ++i ) { @@ -1428,7 +1479,7 @@ int FFMPEG::open_encoder(const char *type, const char *spec) break; } has_audio = 1; - if( scan_options(asset->ff_audio_options, sopts) ) { + if( scan_options(asset->ff_audio_options, sopts, st) ) { eprintf("FFMPEG::open_encoder: bad audio options %s:%s\n", codec_name, filename); ret = 1; @@ -1474,7 +1525,7 @@ int FFMPEG::open_encoder(const char *type, const char *spec) break; } has_video = 1; - if( scan_options(asset->ff_video_options, sopts) ) { + if( scan_options(asset->ff_video_options, sopts, st) ) { eprintf("FFMPEG::open_encoder: bad video options %s:%s\n", codec_name, filename); ret = 1; @@ -1649,11 +1700,12 @@ int FFMPEG::decode_activate() int FFMPEG::encode_activate() { + int ret = 0; if( encoding < 0 ) { encoding = 0; if( !(fmt_ctx->flags & AVFMT_NOFILE) && - avio_open(&fmt_ctx->pb, fmt_ctx->filename, AVIO_FLAG_WRITE) < 0 ) { - fprintf(stderr, "FFMPEG::encode_activate: err opening : %s\n", + (ret=avio_open(&fmt_ctx->pb, fmt_ctx->filename, AVIO_FLAG_WRITE)) < 0 ) { + ff_err(ret, "FFMPEG::encode_activate: err opening : %s\n", fmt_ctx->filename); return 1; } @@ -1662,10 +1714,10 @@ int FFMPEG::encode_activate() char option_path[BCTEXTLEN]; set_option_path(option_path, "format/%s", file_format); read_options(option_path, fopts); - int ret = avformat_write_header(fmt_ctx, &fopts); + ret = avformat_write_header(fmt_ctx, &fopts); av_dict_free(&fopts); if( ret < 0 ) { - fprintf(stderr, "FFMPEG::encode_activate: write header failed %s\n", + ff_err(ret, "FFMPEG::encode_activate: write header failed %s\n", fmt_ctx->filename); return 1; } @@ -1766,19 +1818,15 @@ void FFMPEG::flow_ctl() int FFMPEG::mux_audio(FFrame *frm) { FFPacket pkt; - AVStream *st = frm->fst->st; - AVCodecContext *ctx = st->codec; + FFStream *fst = frm->fst; + AVCodecContext *ctx = fst->st->codec; AVFrame *frame = *frm; AVRational tick_rate = {1, ctx->sample_rate}; frame->pts = av_rescale_q(frm->position, tick_rate, ctx->time_base); int got_packet = 0; - int ret = avcodec_encode_audio2(ctx, pkt, frame, &got_packet); - if( ret >= 0 && got_packet ) { - frm->fst->bs_filter(pkt); - av_packet_rescale_ts(pkt, ctx->time_base, st->time_base); - pkt->stream_index = st->index; - ret = av_interleaved_write_frame(fmt_ctx, pkt); - } + int ret = fst->encode_frame(pkt, frame, got_packet); + if( ret >= 0 && got_packet ) + ret = fst->write_packet(pkt); if( ret < 0 ) ff_err(ret, "FFMPEG::mux_audio"); return ret >= 0 ? 0 : 1; @@ -1787,14 +1835,14 @@ int FFMPEG::mux_audio(FFrame *frm) int FFMPEG::mux_video(FFrame *frm) { FFPacket pkt; - AVStream *st = frm->fst->st; + FFStream *fst = frm->fst; AVFrame *frame = *frm; frame->pts = frm->position; int ret = 1, got_packet = 0; if( fmt_ctx->oformat->flags & AVFMT_RAWPICTURE ) { /* a hack to avoid data copy with some raw video muxers */ pkt->flags |= AV_PKT_FLAG_KEY; - pkt->stream_index = st->index; + pkt->stream_index = fst->st->index; AVPicture *picture = (AVPicture *)frame; pkt->data = (uint8_t *)picture; pkt->size = sizeof(AVPicture); @@ -1802,13 +1850,9 @@ int FFMPEG::mux_video(FFrame *frm) got_packet = 1; } else - ret = avcodec_encode_video2(st->codec, pkt, frame, &got_packet); - if( ret >= 0 && got_packet ) { - frm->fst->bs_filter(pkt); - av_packet_rescale_ts(pkt, st->codec->time_base, st->time_base); - pkt->stream_index = st->index; - ret = av_interleaved_write_frame(fmt_ctx, pkt); - } + ret = fst->encode_frame(pkt, frame, got_packet); + if( ret >= 0 && got_packet ) + ret = fst->write_packet(pkt); if( ret < 0 ) ff_err(ret, "FFMPEG::mux_video"); return ret >= 0 ? 0 : 1; @@ -1856,6 +1900,10 @@ void FFMPEG::run() if( !done ) mux(); } mux(); + for( int i=0; iflush(); + for( int i=0; iflush(); } @@ -2022,6 +2070,11 @@ int FFVideoStream::create_filter(const char *filter_spec, AVCodecContext *src_ctx, AVCodecContext *sink_ctx) { avfilter_register_all(); + AVFilter *filter = avfilter_get_by_name(filter_spec); + if( !filter || filter->inputs->type != AVMEDIA_TYPE_VIDEO ) { + ff_err(AVERROR(EINVAL), "FFVideoStream::create_filter: %s\n", filter_spec); + return -1; + } filter_graph = avfilter_graph_alloc(); AVFilter *buffersrc = avfilter_get_by_name("buffer"); AVFilter *buffersink = avfilter_get_by_name("buffersink"); @@ -2053,6 +2106,11 @@ int FFAudioStream::create_filter(const char *filter_spec, AVCodecContext *src_ctx, AVCodecContext *sink_ctx) { avfilter_register_all(); + AVFilter *filter = avfilter_get_by_name(filter_spec); + if( !filter || filter->inputs->type != AVMEDIA_TYPE_AUDIO ) { + ff_err(AVERROR(EINVAL), "FFAudioStream::create_filter: %s\n", filter_spec); + return -1; + } filter_graph = avfilter_graph_alloc(); AVFilter *buffersrc = avfilter_get_by_name("abuffer"); AVFilter *buffersink = avfilter_get_by_name("abuffersink");