From 152ffc4f666c2059303bd0fc2c4f2dd2bf54cfee Mon Sep 17 00:00:00 2001 From: Derek Kozel Date: Fri, 12 Dec 2025 21:48:57 +0000 Subject: [PATCH] Ported FFmpeg API usage from 4.x to 6.x --- FilmScan.cpp | 37 ++++++++-------- mainwindow.cpp | 113 ++++++++++++++++++++++++++--------------------- mainwindow.h | 1 + videoencoder.cpp | 106 +++++++++++++++++++++----------------------- videoencoder.h | 8 +++- 5 files changed, 139 insertions(+), 126 deletions(-) diff --git a/FilmScan.cpp b/FilmScan.cpp index 2bd73f8..25a2af7 100644 --- a/FilmScan.cpp +++ b/FilmScan.cpp @@ -136,8 +136,9 @@ bool Video::ReadNextFrame(size_t currfnum) if(packet.stream_index == this->streamIdx) { // Decode video frame - avcodec_decode_video2(this->codec, this->frameNative, &done, - &packet); + avcodec_send_packet(this->codec, &packet); + int ret = avcodec_receive_frame(this->codec, this->frameNative); + int done = (ret == 0) ? 1 : 0; // Did we get a complete video frame? if(done) @@ -719,9 +720,6 @@ bool FilmScan::SourceLibAV(const std::string filename) { #ifdef USELIBAV { - // accept any recognized codec - av_register_all(); - vid = new Video; AVDictionary *dict = NULL; @@ -755,7 +753,7 @@ bool FilmScan::SourceLibAV(const std::string filename) vid->streamIdx = -1; for(int i=0; iformat->nb_streams; ++i) { - if(vid->format->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) + if(vid->format->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO) { vid->streamIdx=i; DE = av_dict_get(vid->format->streams[i]->metadata,"timecode",NULL ,0); @@ -810,7 +808,7 @@ bool FilmScan::SourceLibAV(const std::string filename) vid->streamIdx = -1; for(int i=0; iformat->nb_streams; ++i) { - if(vid->format->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) + if(vid->format->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO) { vid->streamIdx=i; break; @@ -832,10 +830,14 @@ bool FilmScan::SourceLibAV(const std::string filename) { // TODO: if it doesn't know, guess based on duration and then validate. // + // Use AVRational from codecpar, or fallback to stream's framerate + AVRational frame_rate = vid->format->streams[vid->streamIdx]->avg_frame_rate; + if(frame_rate.num == 0) frame_rate = vid->format->streams[vid->streamIdx]->r_frame_rate; + int fps = (frame_rate.num > 0) ? frame_rate.num / frame_rate.den : 24; // default to 24fps + this->numFrames = (int)(( vid->format->streams[vid->streamIdx]->duration / - (double)AV_TIME_BASE ) * - vid->format->streams[vid->streamIdx]->codec->time_base.den + + (double)AV_TIME_BASE ) * fps + 0.5); /* FAILED ATTEMPT TO USE LIBAV TO READ IMAGES @@ -856,14 +858,14 @@ bool FilmScan::SourceLibAV(const std::string filename) this->firstFrame = 0; - AVCodecContext *codecOrig; - AVCodec *decoder; + AVCodecParameters *codecpar; + const AVCodec *decoder; - // Get a pointer to the codec context for the video stream - codecOrig=vid->format->streams[vid->streamIdx]->codec; + // Get a pointer to the codec parameters for the video stream + codecpar=vid->format->streams[vid->streamIdx]->codecpar; // Find the decoder for the video stream - decoder=avcodec_find_decoder(codecOrig->codec_id); + decoder=avcodec_find_decoder(codecpar->codec_id); if(decoder==NULL) { avformat_close_input(&(vid->format)); @@ -872,16 +874,15 @@ bool FilmScan::SourceLibAV(const std::string filename) throw AeoException("Unsupported codec."); } - // Copy codec context + // Create and configure codec context vid->codec = avcodec_alloc_context3(decoder); - if(avcodec_copy_context(vid->codec, codecOrig) != 0) + if(avcodec_parameters_to_context(vid->codec, codecpar) < 0) { avformat_close_input(&(vid->format)); delete vid; vid = NULL; - throw AeoException("Couldn't copy codec context"); + throw AeoException("Couldn't copy codec parameters to context"); } - avcodec_close(codecOrig); // Open codec if(avcodec_open2(vid->codec, decoder, NULL)<0) diff --git a/mainwindow.cpp b/mainwindow.cpp index 550dfea..8b7cb3e 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -2240,7 +2240,7 @@ static int write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AV /* Add an output stream. */ static void add_stream(OutputStream *ost, AVFormatContext *oc, - AVCodec **codec, + const AVCodec **codec, enum AVCodecID codec_id) { AVCodecContext *c; @@ -2255,16 +2255,23 @@ static void add_stream(OutputStream *ost, AVFormatContext *oc, } // allocid: MainWindowStream01 - ost->st = avformat_new_stream(oc, *codec); + ost->st = avformat_new_stream(oc, NULL); if (!ost->st) { fprintf(stderr, "Could not allocate stream\n"); exit(1); } - av_log(NULL, AV_LOG_INFO, - "ALLOC new: MainWindowStream01 ost->st->codec = %p\n", - ost->st->codec); ost->st->id = oc->nb_streams-1; - c = ost->st->codec; + + // Allocate codec context + ost->enc = avcodec_alloc_context3(*codec); + if (!ost->enc) { + fprintf(stderr, "Could not allocate codec context\n"); + exit(1); + } + av_log(NULL, AV_LOG_INFO, + "ALLOC new: MainWindowStream01 ost->enc = %p\n", + ost->enc); + c = ost->enc; switch ((*codec)->type) { case AVMEDIA_TYPE_AUDIO: @@ -2389,14 +2396,14 @@ static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt, return frame; } -static void open_audio(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg) +static void open_audio(AVFormatContext *oc, const AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg) { AVCodecContext *c; int nb_samples; int ret; AVDictionary *opt = NULL; - c = ost->st->codec; + c = ost->enc; /* open it */ av_dict_copy(&opt, opt_arg, 0); @@ -2417,7 +2424,7 @@ static void open_audio(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, A #define AV_CODEC_CAP_VARIABLE_FRAME_SIZE CODEC_CAP_VARIABLE_FRAME_SIZE #endif - if(c->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) + if(codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) nb_samples = 10000; else nb_samples = c->frame_size; @@ -2470,15 +2477,15 @@ AVFrame *MainWindow::get_audio_frame(OutputStream *ost) avr_one.num = avr_one.den = 1; /* check if we want to generate more frames */ - if (av_compare_ts(ost->next_pts, ost->st->codec->time_base, + if (av_compare_ts(ost->next_pts, ost->enc->time_base, STREAM_DURATION, avr_one) >= 0) return NULL; av_log(NULL, AV_LOG_INFO, "Audio generate nb_samples = %d x%d\n", - frame->nb_samples, ost->st->codec->channels); + frame->nb_samples, ost->enc->channels); for (j = 0; j nb_samples; j++) { v = (int)(sin(ost->t) * 10000); - for (i = 0; i < ost->st->codec->channels; i++) + for (i = 0; i < ost->enc->channels; i++) *q++ = v; ost->t += ost->tincr; ost->tincr += ost->tincr2; @@ -2506,7 +2513,7 @@ int MainWindow::write_audio_frame(AVFormatContext *oc, OutputStream *ost) int dst_nb_samples; av_init_packet(&pkt); - c = ost->st->codec; + c = ost->enc; #if 0 frame = get_audio_frame(ost); @@ -2551,8 +2558,16 @@ int MainWindow::write_audio_frame(AVFormatContext *oc, OutputStream *ost) frame->pts = av_rescale_q(ost->samples_count, r, c->time_base); ost->samples_count += dst_nb_samples; - ret = avcodec_encode_audio2(c, &pkt, frame, &got_packet); + ret = avcodec_send_frame(c, frame); if (ret < 0) { + fprintf(stderr, "Error sending audio frame to encoder: %s\n", aeo_av_err2str(ret)); + exit(1); + } + + got_packet = 0; + ret = avcodec_receive_packet(c, &pkt); + if (ret == 0) got_packet = 1; + else if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { fprintf(stderr, "Error encoding audio frame: %s\n", aeo_av_err2str(ret)); exit(1); } @@ -2596,10 +2611,10 @@ static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height) return picture; } -static void open_video(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg) +static void open_video(AVFormatContext *oc, const AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg) { int ret; - AVCodecContext *c = ost->st->codec; + AVCodecContext *c = ost->enc; AVDictionary *opt = NULL; av_log(NULL, AV_LOG_INFO, "av_dict_copy(&opt, opt_arg, 0)\n"); @@ -2715,11 +2730,11 @@ static void fill_rgba_image(AVFrame *pict, int frame_index, AVFrame *MainWindow::get_video_frame(OutputStream *ost) { - AVCodecContext *c = ost->st->codec; + AVCodecContext *c = ost->enc; #if 0 /* check if we want to generate more frames */ - if (av_compare_ts(ost->next_pts, ost->st->codec->time_base, + if (av_compare_ts(ost->next_pts, ost->enc->time_base, STREAM_DURATION, (AVRational){ 1, 1 }) >= 0) return NULL; @@ -2747,7 +2762,7 @@ AVFrame *MainWindow::get_video_frame(OutputStream *ost) } //#elif 0 /* check if we want to generate more frames */ - if (av_compare_ts(ost->next_pts, ost->st->codec->time_base, + if (av_compare_ts(ost->next_pts, ost->enc->time_base, STREAM_DURATION, (AVRational){ 1, 1 }) >= 0) return NULL; @@ -2841,7 +2856,7 @@ int MainWindow::write_video_frame(AVFormatContext *oc, OutputStream *ost) pkt.data = NULL; pkt.size = 0; - c = ost->st->codec; + c = ost->enc; av_log(NULL, AV_LOG_INFO, "frame = get_video_frame(ost)\n"); frame = get_video_frame(ost); @@ -2850,9 +2865,17 @@ int MainWindow::write_video_frame(AVFormatContext *oc, OutputStream *ost) av_init_packet(&pkt); /* encode the image */ - av_log(NULL, AV_LOG_INFO, "ret = avcodec_encode_video2(c, &pkt, frame, &got_packet)\n"); - ret = avcodec_encode_video2(c, &pkt, frame, &got_packet); + av_log(NULL, AV_LOG_INFO, "ret = avcodec_send_frame/receive_packet(c, frame)\n"); + ret = avcodec_send_frame(c, frame); if (ret < 0) { + fprintf(stderr, "Error sending video frame to encoder: %s\n", aeo_av_err2str(ret)); + exit(1); + } + + got_packet = 0; + ret = avcodec_receive_packet(c, &pkt); + if (ret == 0) got_packet = 1; + else if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { fprintf(stderr, "Error encoding video frame: %s\n", aeo_av_err2str(ret)); exit(1); } @@ -2876,9 +2899,9 @@ static void close_stream(AVFormatContext *oc, OutputStream *ost) { // allocid: MainWindowStream01 av_log(NULL, AV_LOG_INFO, - "ALLOC del: MainWindowStream01 ost->st->codec = %p\n", - ost->st->codec); - avcodec_close(ost->st->codec); + "ALLOC del: MainWindowStream01 ost->enc = %p\n", + ost->enc); + avcodec_close(ost->enc); // allocid: MainWindowFrame01 // allocid: MainWindowFrame03 @@ -2923,10 +2946,10 @@ int MainWindow::MuxMain(const char *fn_arg, long startFrame, long numFrames, memset(&video_st, 0, sizeof(OutputStream)); memset(&audio_st, 0, sizeof(OutputStream)); const char *filename = NULL; - AVOutputFormat *fmt = NULL; + const AVOutputFormat *fmt = NULL; AVFormatContext *oc = NULL; - AVCodec *audio_codec = NULL; - AVCodec *video_codec = NULL; + const AVCodec *audio_codec = NULL; + const AVCodec *video_codec = NULL; int ret; int have_video = 0, have_audio = 0; int encode_video = 0, encode_audio = 0; @@ -2943,18 +2966,6 @@ int MainWindow::MuxMain(const char *fn_arg, long startFrame, long numFrames, throw AeoException("Invalid call to MuxMain"); } - // Call only once (I think libav can handle additional calls all right, - // but just in case it doesn't...) - static bool needRegisterAll = true; - if(needRegisterAll) - { - /* Initialize libavcodec, and register all codecs and formats. */ - av_log(NULL, AV_LOG_INFO, "av_register_all()\n"); - - av_register_all(); - needRegisterAll = false; - } - filename = argv[1]; /* if (argc > 3 && !strcmp(argv[2], "-flags")) { @@ -3113,8 +3124,8 @@ int MainWindow::MuxMain(const char *fn_arg, long startFrame, long numFrames, while (encode_video || encode_audio) { /* select the stream to encode */ if (encode_video && - (!encode_audio || av_compare_ts(video_st.next_pts, video_st.st->codec->time_base, - audio_st.next_pts, audio_st.st->codec->time_base) <= 0)) { + (!encode_audio || av_compare_ts(video_st.next_pts, video_st.enc->time_base, + audio_st.next_pts, audio_st.enc->time_base) <= 0)) { av_log(NULL, AV_LOG_INFO, "encode_video = !write_video_frame(oc, &video_st)\n"); encode_video = !write_video_frame(oc, &video_st); } else { @@ -4091,19 +4102,21 @@ void MainWindow::QueueImportVFB() QDomDocument xmlBOM; // Set data into the QDomDocument for processing - QDomDocument::ParseResult parse = xmlBOM.setContent(&xmlFile); + QString errorMsg; + int errorLine, errorColumn; + bool parseSuccess = xmlBOM.setContent(&xmlFile, &errorMsg, &errorLine, &errorColumn); xmlFile.close(); // nb: the 6.5 docs say casting to bool returns true if there is an // error and false otherwise, but the opposite is the case. - if(!bool(parse)) + if(!parseSuccess) { QMessageBox msgError; msgError.setText( QString("Error reading XML file, line %1, column %2
%3") - .arg(parse.errorLine) - .arg(parse.errorColumn) - .arg(parse.errorMessage.toHtmlEscaped())); + .arg(errorLine) + .arg(errorColumn) + .arg(errorMsg.toHtmlEscaped())); msgError.setIcon(QMessageBox::Critical); msgError.setWindowTitle("Error reading XML file"); msgError.exec(); @@ -4210,7 +4223,7 @@ void MainWindow::QueueImportVFB() "Do you wish to name the output files " "individually or use a base name plus a count?"). arg(clipList.size()).arg(nSlots)); - clipList.resize(nSlots); + while (clipList.size() > nSlots) clipList.removeLast(); } msg.setWindowTitle("Multiple clips found"); @@ -4272,7 +4285,7 @@ void MainWindow::QueueImportVFB() QMessageBox::Ok); if(btn != QMessageBox::Ok) return; - clipList.resize(1); + while (clipList.size() > 1) clipList.removeLast(); } QList taskList; diff --git a/mainwindow.h b/mainwindow.h index 51e7f4a..875cbf8 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -112,6 +112,7 @@ class OutputStream { int requestedTimeBase; AVStream *st; + AVCodecContext *enc; /* pts of the next frame that will be generated */ int64_t next_pts; diff --git a/videoencoder.cpp b/videoencoder.cpp index 1da0baa..1ee9ba2 100644 --- a/videoencoder.cpp +++ b/videoencoder.cpp @@ -100,9 +100,13 @@ VideoEncoder::VideoEncoder(const char *filename) { int i; + outputFilename = strdup(filename); + outFmt = NULL; audioCodec = NULL; videoCodec = NULL; + audioCtx = NULL; + videoCtx = NULL; audioStream = NULL; videoStream = NULL; @@ -121,15 +125,9 @@ VideoEncoder::VideoEncoder(const char *filename) if(sizeof(filename) >= 1024) THROW("Filename too long for libav's hardcoded length setting"); - av_log(NULL, AV_LOG_INFO, "av_register_all()\n"); - av_register_all(); - - av_log(NULL, AV_LOG_INFO, "avcodec_register_all()\n"); - avcodec_register_all(); - // *** Create the output context based on the filename *** av_log(NULL, AV_LOG_INFO, "avformat_alloc_output_context2()\n"); - avformat_alloc_output_context2(&outFmt, NULL, NULL, filename); + avformat_alloc_output_context2(&outFmt, NULL, NULL, outputFilename); if(!outFmt) { @@ -137,13 +135,8 @@ VideoEncoder::VideoEncoder(const char *filename) outFmt = avformat_alloc_context(); if(!outFmt) THROW("Could not allocate output context"); - // filename max length is hardcoded at 1024 characters, incl. NULL - if(sizeof(outFmt->filename) <= strlen(filename)) - THROW("Filename too long for libav's hardcoded length setting"); - strcpy(outFmt->filename, filename); - av_log(NULL, AV_LOG_INFO, "--av_guess_format()\n"); - outFmt->oformat = av_guess_format(NULL, filename, NULL); + outFmt->oformat = av_guess_format(NULL, outputFilename, NULL); // if the filename doesn't yield a suitable guess, use mpeg if(!outFmt->oformat) outFmt->oformat = av_guess_format("mpeg", NULL, NULL); if(!outFmt->oformat) THROW("No suitable output file format found."); @@ -161,59 +154,62 @@ VideoEncoder::VideoEncoder(const char *filename) videoCodec = avcodec_find_encoder_by_name("prores_ks"); if (!videoCodec) THROW("video Codec not found"); + this->videoCtx = avcodec_alloc_context3(videoCodec); av_log(NULL, AV_LOG_INFO, "avformat_new_stream(outFmt, videoCodec)\n"); - videoStream = avformat_new_stream(outFmt, videoCodec); + videoStream = avformat_new_stream(outFmt, NULL); if(!videoStream) THROW("could not create video stream"); av_log(NULL, AV_LOG_INFO, "videoStream->id = outFmt->nb_streams - 1\n"); videoStream->id = outFmt->nb_streams - 1; - //videoCtx = avcodec_alloc_context3(videoCodec); - //if (!videoCtx) THROW("Could not allocate video codec context"); - av_log(NULL, AV_LOG_INFO, "videoCtx = videoStream->codec\n"); - AVCodecContext *videoCtx = videoStream->codec; + av_log(NULL, AV_LOG_INFO, "Configuring member videoCtx\n"); av_log(NULL, AV_LOG_INFO, "videoCtx->bit_rate = 400000\n"); av_log(NULL, AV_LOG_INFO, "videoCtx->width = 640\n"); av_log(NULL, AV_LOG_INFO, "videoCtx->height = 480\n"); - videoCtx->bit_rate = 400000; - videoCtx->width = 640; - videoCtx->height = 480; + this->videoCtx->bit_rate = 400000; + this->videoCtx->width = 640; + this->videoCtx->height = 480; av_log(NULL, AV_LOG_INFO, "videoStream->time_base = 1/25\n"); videoStream->time_base.num = 1; videoStream->time_base.den = 25; av_log(NULL, AV_LOG_INFO, "videoCtx->time_base = videoStream->time_base\n"); - videoCtx->time_base = videoStream->time_base; + this->videoCtx->time_base = videoStream->time_base; - //videoCtx->pix_fmt = AV_PIX_FMT_YUV420P; + //this->videoCtx->pix_fmt = AV_PIX_FMT_YUV420P; av_log(NULL, AV_LOG_INFO, "videoCtx->pix_fmt = AV_PIX_FMT_YUVA444P10LE\n"); - videoCtx->pix_fmt = AV_PIX_FMT_YUVA444P10LE; + this->videoCtx->pix_fmt = AV_PIX_FMT_YUVA444P10LE; if(videoCodec->pix_fmts) { for(i=0; videoCodec->pix_fmts[i]; i++) { - if(videoCodec->pix_fmts[i] == videoCtx->pix_fmt) + if(videoCodec->pix_fmts[i] == this->videoCtx->pix_fmt) break; } - if(videoCodec->pix_fmts[i] != videoCtx->pix_fmt) + if(videoCodec->pix_fmts[i] != this->videoCtx->pix_fmt) { av_log(NULL, AV_LOG_INFO, "videoCtx->pix_fmt = videoCodec->pix_fmts[0]\n"); - videoCtx->pix_fmt = videoCodec->pix_fmts[0]; + this->videoCtx->pix_fmt = videoCodec->pix_fmts[0]; } } av_log(NULL, AV_LOG_INFO, "videoCtx->gop_size = 12\n"); - videoCtx->gop_size = 12; // emit intra frame no more than every 12 frames + this->videoCtx->gop_size = 12; // emit intra frame no more than every 12 frames // If the container requires global headers, set the encoder to same. if(outFmt->oformat->flags & AVFMT_GLOBALHEADER) { av_log(NULL, AV_LOG_INFO, "videoCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER\n"); - videoCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + this->videoCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; } + + // Copy codec parameters to stream + if (avcodec_parameters_from_context(videoStream->codecpar, this->videoCtx) < 0) + THROW("Failed to copy codec parameters to stream"); + // ****************************** // *** CONFIGURE AUDIO STREAM *** // ****************************** @@ -458,16 +454,10 @@ void VideoEncoder::Open() { if(!outFmt) return; - av_log(NULL, AV_LOG_INFO, "videoCtx = videoStream->codec\n"); - AVCodecContext *videoCtx = videoStream->codec; - -#ifdef DO_AUDIO - av_log(NULL, AV_LOG_INFO, "AVCodecContext *audioCtx = audioStream->codec\n"); - AVCodecContext *audioCtx = audioStream->codec; -#endif + av_log(NULL, AV_LOG_INFO, "Using member videoCtx and audioCtx\n"); av_log(NULL, AV_LOG_INFO, "avcodec_open2(videoCtx, videoCodec, NULL)\n"); - if(avcodec_open2(videoCtx, videoCodec, NULL) < 0) + if(avcodec_open2(this->videoCtx, videoCodec, NULL) < 0) THROW("Could not open video codec"); #ifdef DO_AUDIO @@ -483,9 +473,9 @@ void VideoEncoder::Open() av_log(NULL, AV_LOG_INFO, "videoFrameOut->format = videoCtx->pix_fmt\n"); av_log(NULL, AV_LOG_INFO, "videoFrameOut->width = videoCtx->width\n"); av_log(NULL, AV_LOG_INFO, "videoFrameOut->height = videoCtx->height\n"); - videoFrameOut->format = videoCtx->pix_fmt; - videoFrameOut->width = videoCtx->width; - videoFrameOut->height = videoCtx->height; + videoFrameOut->format = this->videoCtx->pix_fmt; + videoFrameOut->width = this->videoCtx->width; + videoFrameOut->height = this->videoCtx->height; av_log(NULL, AV_LOG_INFO, "av_frame_get_buffer(videoFrameOut, 32)\n"); if(av_frame_get_buffer(videoFrameOut, 32) < 0) THROW("Could not allocate videoFrameOut buffer"); @@ -495,14 +485,14 @@ void VideoEncoder::Open() "SWS_BICUBIC, NULL, NULL, NULL)\n", videoFrameIn->width, videoFrameIn->height, av_get_pix_fmt_name(AVPixelFormat(videoFrameIn->format)), - videoCtx->width, videoCtx->height, + this->videoCtx->width, this->videoCtx->height, av_get_pix_fmt_name(AVPixelFormat(videoFrameOut->format)) ); videoRescaleCtx = sws_getContext( videoFrameIn->width, videoFrameIn->height, AVPixelFormat(videoFrameIn->format), - videoCtx->width, videoCtx->height, - AVPixelFormat(videoCtx->pix_fmt), + this->videoCtx->width, this->videoCtx->height, + AVPixelFormat(this->videoCtx->pix_fmt), SWS_BICUBIC, NULL, NULL, NULL); if(!videoRescaleCtx) THROW("Couldn't initialize video rescale context"); @@ -542,8 +532,8 @@ void VideoEncoder::Open() if (!(outFmt->flags & AVFMT_NOFILE)) { av_log(NULL, AV_LOG_INFO, - "avio_open(&outFmt->pb, outFmt->filename, AVIO_FLAG_WRITE)\n"); - if(avio_open(&outFmt->pb, outFmt->filename, AVIO_FLAG_WRITE) < 0) + "avio_open(&outFmt->pb, outputFilename, AVIO_FLAG_WRITE)\n"); + if(avio_open(&outFmt->pb, outputFilename, AVIO_FLAG_WRITE) < 0) THROW("Could not open output file."); } @@ -562,11 +552,11 @@ void VideoEncoder::Close() THROW("Error writing output file trailer"); #ifdef DO_AUDIO - av_log(NULL, AV_LOG_INFO, "avcodec_close(audioStream->codec)\n"); - avcodec_close(audioStream->codec); + av_log(NULL, AV_LOG_INFO, "avcodec_close(audioCtx)\n"); + avcodec_close(this->audioCtx); #endif - av_log(NULL, AV_LOG_INFO, "avcodec_close(videoStream->codec)\n"); - avcodec_close(videoStream->codec); + av_log(NULL, AV_LOG_INFO, "avcodec_close(videoCtx)\n"); + avcodec_close(this->videoCtx); if(!(outFmt->flags & AVFMT_NOFILE)) { @@ -616,8 +606,7 @@ void VideoEncoder::WriteVideoFrame(const FrameTexture *frame) //av_frame_make_writable(this->videoFrameIn); //memcpy(this->videoFrameIn->data[0], frame->buf, frame->bufSize); - av_log(NULL, AV_LOG_INFO, "videoCtx = this->videoStream->codec\n"); - AVCodecContext *videoCtx = this->videoStream->codec; + av_log(NULL, AV_LOG_INFO, "Using member videoCtx\n"); /* when we pass a frame to the encoder, it may keep a reference to it * internally; @@ -659,15 +648,20 @@ void VideoEncoder::WriteVideoFrame(const FrameTexture *frame) av_log(NULL, AV_LOG_INFO, "v_packet_rescale_ts(&pkt, videoCtx->time_base, " "videoStream->time_base)\n"); - av_packet_rescale_ts(&pkt, videoCtx->time_base, + av_packet_rescale_ts(&pkt, this->videoCtx->time_base, this->videoStream->time_base); int got_packet; av_log(NULL, AV_LOG_INFO, - "avcodec_encode_video2(videoCtx, &pkt, videoFrameOut, &got)\n"); - ret = avcodec_encode_video2( - videoCtx, &pkt, this->videoFrameOut, &got_packet); - if(ret < 0) THROW("failed to encode video frame"); + "avcodec_send_frame/receive_packet(videoCtx, &pkt, videoFrameOut)\n"); + ret = avcodec_send_frame(this->videoCtx, this->videoFrameOut); + if(ret < 0) THROW("failed to send frame to encoder"); + + got_packet = 0; + ret = avcodec_receive_packet(this->videoCtx, &pkt); + if(ret == 0) got_packet = 1; + else if(ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) + THROW("failed to receive encoded packet"); if(got_packet) { diff --git a/videoencoder.h b/videoencoder.h index c808ee7..4b71db6 100644 --- a/videoencoder.h +++ b/videoencoder.h @@ -85,10 +85,14 @@ class VideoEncoder private: AVFormatContext *outFmt; + char *outputFilename; // Store filename // corresponding variable in muxing.c - AVCodec *audioCodec; // audio_codec - AVCodec *videoCodec; // video_codec + const AVCodec *audioCodec; // audio_codec + const AVCodec *videoCodec; // video_codec + + AVCodecContext *audioCtx; // audio codec context + AVCodecContext *videoCtx; // video codec context AVStream *audioStream; // audio_st->st AVStream *videoStream; // video_st->st