X-Git-Url: http://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.0%2Fcinelerra%2Fffmpeg.C;h=2f1a1987cf6cd7fe6397da5ccb43381d4b82827d;hb=5aad2133f228b736f033d6c48e1629078b858286;hp=68ff296d0013581d695f2bb713d75d4554f764eb;hpb=91efd376233a15f6572e6f68d28a5bee69797e87;p=goodguy%2Fhistory.git diff --git a/cinelerra-5.0/cinelerra/ffmpeg.C b/cinelerra-5.0/cinelerra/ffmpeg.C index 68ff296d..2f1a1987 100644 --- a/cinelerra-5.0/cinelerra/ffmpeg.C +++ b/cinelerra-5.0/cinelerra/ffmpeg.C @@ -18,6 +18,8 @@ #include "fileffmpeg.h" #include "file.h" #include "ffmpeg.h" +#include "libdv.h" +#include "libmjpeg.h" #include "mainerror.h" #include "mwindow.h" #include "vframe.h" @@ -409,6 +411,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) { @@ -596,6 +621,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) { @@ -702,6 +737,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) { @@ -899,8 +943,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) @@ -940,13 +984,15 @@ AVRational FFMPEG::check_frame_rate(AVCodec *codec, double frame_rate) return max_err < 0.0001 ? best_rate : (AVRational) { 0, 0 }; } -AVRational FFMPEG::to_sample_aspect_ratio(double aspect_ratio) +AVRational FFMPEG::to_sample_aspect_ratio(Asset *asset) { #if 1 - int height = 1000000, width = height * aspect_ratio; + double display_aspect = asset->width / (double)asset->height; + double sample_aspect = asset->aspect_ratio / display_aspect; + int width = 1000000, height = width * sample_aspect + 0.5; float w, h; MWindow::create_aspect_ratio(w, h, width, height); - return (AVRational){(int)w, (int)h}; + return (AVRational){(int)h, (int)w}; #else // square pixels return (AVRational){1, 1}; @@ -1293,7 +1339,13 @@ int FFMPEG::open_decoder() AVStream *st = fmt_ctx->streams[i]; if( st->duration == AV_NOPTS_VALUE ) bad_time = 1; AVCodecContext *avctx = st->codec; + const AVCodecDescriptor *codec_desc = avcodec_descriptor_get(avctx->codec_id); + if( !codec_desc ) continue; if( avctx->codec_type == AVMEDIA_TYPE_VIDEO ) { + if( avctx->width < 1 ) continue; + if( avctx->height < 1 ) continue; + AVRational framerate = av_guess_frame_rate(fmt_ctx, st, 0); + if( framerate.num < 1 ) continue; has_video = 1; FFVideoStream *vid = new FFVideoStream(this, st, i); int vidx = ffvideo.size(); @@ -1301,7 +1353,6 @@ int FFMPEG::open_decoder() ffvideo.append(vid); vid->width = avctx->width; vid->height = avctx->height; - AVRational framerate = av_guess_frame_rate(fmt_ctx, st, 0); vid->frame_rate = !framerate.den ? 0 : (double)framerate.num / framerate.den; double secs = to_secs(st->duration, st->time_base); vid->length = secs * vid->frame_rate; @@ -1312,6 +1363,8 @@ int FFMPEG::open_decoder() vid->create_filter(opt_video_filter, avctx,avctx); } else if( avctx->codec_type == AVMEDIA_TYPE_AUDIO ) { + if( avctx->channels < 1 ) continue; + if( avctx->sample_rate < 1 ) continue; has_audio = 1; FFAudioStream *aud = new FFAudioStream(this, st, i); int aidx = ffaudio.size(); @@ -1398,6 +1451,10 @@ int FFMPEG::open_encoder(const char *type, const char *spec) return 1; } + if( !strcmp(codec_name, CODEC_TAG_DVSD) ) strcpy(codec_name, "dv"); + else if( !strcmp(codec_name, CODEC_TAG_MJPEG) ) strcpy(codec_name, "mjpeg"); + else if( !strcmp(codec_name, CODEC_TAG_JPEG) ) strcpy(codec_name, "jpeg"); + int ret = 0; ff_lock("FFMPEG::open_encoder"); FFStream *fst = 0; @@ -1518,7 +1575,7 @@ int FFMPEG::open_encoder(const char *type, const char *spec) vid->height = asset->height; ctx->height = (vid->height+3) & ~3; vid->frame_rate = asset->frame_rate; - ctx->sample_aspect_ratio = to_sample_aspect_ratio(asset->aspect_ratio); + ctx->sample_aspect_ratio = to_sample_aspect_ratio(asset); ctx->pix_fmt = codec->pix_fmts ? codec->pix_fmts[0] : AV_PIX_FMT_YUV420P; AVRational frame_rate = check_frame_rate(codec, vid->frame_rate); if( !frame_rate.num || !frame_rate.den ) { @@ -1538,6 +1595,9 @@ int FFMPEG::open_encoder(const char *type, const char *spec) } } if( !ret ) { + if( fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER ) + st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + ret = avcodec_open2(st->codec, codec, &sopts); if( ret < 0 ) { ff_err(ret,"FFMPEG::open_encoder"); @@ -1549,8 +1609,6 @@ int FFMPEG::open_encoder(const char *type, const char *spec) ret = 0; } if( !ret ) { - if( fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER ) - st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; if( fst && bsfilter[0] ) fst->add_bsfilter(bsfilter, !bsargs[0] ? 0 : bsargs); } @@ -1776,19 +1834,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; @@ -1797,14 +1851,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); @@ -1812,13 +1866,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; @@ -1866,6 +1916,10 @@ void FFMPEG::run() if( !done ) mux(); } mux(); + for( int i=0; iflush(); + for( int i=0; iflush(); } @@ -2032,6 +2086,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"); @@ -2063,6 +2122,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");