From 2d8ee7ae9c2f42d8c6f2d5dcc8949ef989ebd7af Mon Sep 17 00:00:00 2001 From: Good Guy Date: Mon, 17 Aug 2015 11:08:50 -0600 Subject: [PATCH] add missing ffmpeg encoder flush, bdwrite leaks + fixes --- cinelerra-5.0/cinelerra/bdcreate.C | 4 +- cinelerra-5.0/cinelerra/bdwrite.C | 39 +++++++++++----- cinelerra-5.0/cinelerra/ffmpeg.C | 74 ++++++++++++++++++++++-------- cinelerra-5.0/cinelerra/ffmpeg.h | 5 ++ 4 files changed, 91 insertions(+), 31 deletions(-) diff --git a/cinelerra-5.0/cinelerra/bdcreate.C b/cinelerra-5.0/cinelerra/bdcreate.C index 50748492..86a2a690 100644 --- a/cinelerra-5.0/cinelerra/bdcreate.C +++ b/cinelerra-5.0/cinelerra/bdcreate.C @@ -139,13 +139,13 @@ int CreateBD_Thread::create_bd_jobs(ArrayList *jobs, fprintf(fp,"#!/bin/bash -ex\n"); fprintf(fp,"mkdir -p $1/udfs\n"); fprintf(fp,"sz=`du -sb $1/bd.m2ts | sed -e 's/[ \t].*//'`\n"); - fprintf(fp,"blks=$((sz/2048 + 512))\n"); + fprintf(fp,"blks=$((sz/2048 + 4096))\n"); fprintf(fp,"mkudffs $1/bd.udfs $blks\n"); fprintf(fp,"mount -o loop $1/bd.udfs $1/udfs\n"); fprintf(fp,"%s/bdwrite $1/udfs $1/bd.m2ts\n",exe_path); fprintf(fp,"umount $1/udfs\n"); fprintf(fp,"echo To burn bluray, load blank media and run:\n"); - fprintf(fp,"echo dd if=$1/bd.udfs 0f=/dev/bd bs=2048000\n"); + fprintf(fp,"echo dd if=$1/bd.udfs of=/dev/bd bs=2048000\n"); fprintf(fp,"\n"); fclose(fp); diff --git a/cinelerra-5.0/cinelerra/bdwrite.C b/cinelerra-5.0/cinelerra/bdwrite.C index 3ac4b0ff..ad331169 100644 --- a/cinelerra-5.0/cinelerra/bdwrite.C +++ b/cinelerra-5.0/cinelerra/bdwrite.C @@ -719,7 +719,9 @@ public: int write(); mpls_pi() {} - ~mpls_pi() {} + ~mpls_pi() { + clip.remove_all_objects(); + } }; class _mpls_plm { @@ -1168,7 +1170,10 @@ public: strcpy(filename, fn); brk = 0; pidx = 0; pgm_pid = -1; still = 0; } - ~media_info() { streams.remove_all_objects(); } + ~media_info() { + streams.remove_all_objects(); + programs.remove_all_objects(); + } int scan(); int scan(AVFormatContext *fmt_ctx); @@ -2458,13 +2463,10 @@ int media_info::scan() av_dict_set(&fopts, "threads", "auto", 0); int ret = avformat_open_input(&fmt_ctx, filename, NULL, &fopts); av_dict_free(&fopts); + if( ret < 0 ) return ret; + ret = avformat_find_stream_info(fmt_ctx, NULL); - if( ret >= 0 ) - ret = avformat_find_stream_info(fmt_ctx, NULL); - - if( ret >= 0 ) { - bit_rate = fmt_ctx->bit_rate; - } + bit_rate = fmt_ctx->bit_rate; int ep_pid = -1; for( int i=0; ret>=0 && i<(int)fmt_ctx->nb_streams; ++i ) { @@ -2519,8 +2521,22 @@ int media_info::scan() pgm->ep_pid = ep_pid; pgm->pmt_pid = 0x1000; pgm->pcr_pid = 0x100; - for( int jj=0; jjduration = 0; + for( int jj=0; jjstreams[jj]; + AVMediaType type = st->codec->codec_type; + switch( type ) { + case AVMEDIA_TYPE_VIDEO: + case AVMEDIA_TYPE_AUDIO: + break; + default: + continue; + } pgm->strm_idx.append(jj); + if( pgm->duration < st->duration ) + pgm->duration = av_rescale_q(st->duration, st->time_base, clk45k); + } + programs.append(pgm); } for( int ii=0; ii= 0 ) ret = scan(fmt_ctx); - if( fmt_ctx ) - avformat_close_input(&fmt_ctx); + for( int i=0; i<(int)fmt_ctx->nb_streams; ++i ) + avcodec_close(fmt_ctx->streams[i]->codec); + avformat_close_input(&fmt_ctx); return ret; } diff --git a/cinelerra-5.0/cinelerra/ffmpeg.C b/cinelerra-5.0/cinelerra/ffmpeg.C index 68ff296d..decb3d00 100644 --- a/cinelerra-5.0/cinelerra/ffmpeg.C +++ b/cinelerra-5.0/cinelerra/ffmpeg.C @@ -409,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) { @@ -596,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) { @@ -702,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) { @@ -1776,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; @@ -1797,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); @@ -1812,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; @@ -1866,6 +1900,10 @@ void FFMPEG::run() if( !done ) mux(); } mux(); + for( int i=0; iflush(); + for( int i=0; iflush(); } diff --git a/cinelerra-5.0/cinelerra/ffmpeg.h b/cinelerra-5.0/cinelerra/ffmpeg.h index 28b19148..931e9c4d 100644 --- a/cinelerra-5.0/cinelerra/ffmpeg.h +++ b/cinelerra-5.0/cinelerra/ffmpeg.h @@ -77,9 +77,12 @@ public: virtual int encode_activate(); virtual int decode_activate(); int read_packet(); + int write_packet(FFPacket &pkt); + int flush(); int decode(AVFrame *frame); virtual int decode_frame(AVFrame *frame, int &got_frame) = 0; + virtual int encode_frame(FFPacket &pkt, AVFrame *frame, int &got_frame) = 0; virtual int init_frame(AVFrame *frame) = 0; virtual int create_filter(const char *filter_spec, AVCodecContext *src_ctx, AVCodecContext *sink_ctx) = 0; @@ -153,6 +156,7 @@ public: virtual ~FFAudioStream(); int load_history(uint8_t **data, int len); int decode_frame(AVFrame *frame, int &got_frame); + int encode_frame(FFPacket &pkt, AVFrame *frame, int &got_frame); int create_filter(const char *filter_spec, AVCodecContext *src_ctx, AVCodecContext *sink_ctx); @@ -183,6 +187,7 @@ public: FFVideoStream(FFMPEG *ffmpeg, AVStream *strm, int idx); virtual ~FFVideoStream(); int decode_frame(AVFrame *frame, int &got_frame); + int encode_frame(FFPacket &pkt, AVFrame *frame, int &got_frame); int create_filter(const char *filter_spec, AVCodecContext *src_ctx, AVCodecContext *sink_ctx); -- 2.26.2