File 0001-fixed-encoding-of-silent-audio-file.patch of Package DVDStyler
From e3cf3b06d521973303db567e29984b44b112269d Mon Sep 17 00:00:00 2001
From: ntalex <ntalex@sf.net>
Date: Wed, 17 Nov 2021 20:08:46 +0100
Subject: [PATCH] fixed encoding of silent audio file
---
src/mediaenc_ffmpeg.cpp | 199 +++++++++++++++++++++++++---------------
src/mediaenc_ffmpeg.h | 6 +-
2 files changed, 130 insertions(+), 75 deletions(-)
diff --git a/src/mediaenc_ffmpeg.cpp b/src/mediaenc_ffmpeg.cpp
index 01db671..c591458 100644
--- a/src/mediaenc_ffmpeg.cpp
+++ b/src/mediaenc_ffmpeg.cpp
@@ -45,11 +45,11 @@ wxFfmpegMediaEncoder::wxFfmpegMediaEncoder(int threadCount) {
m_audioCodec = NULL;
m_nextVideoPts = 0;
m_nextAudioPts = 0;
- m_samples = NULL;
m_audioFrame = NULL;
m_picture = NULL;
m_imgConvertCtx = NULL;
m_videoOutbuf = NULL;
+ m_audioFile = NULL;
}
wxFfmpegMediaEncoder::~wxFfmpegMediaEncoder() {
@@ -74,6 +74,18 @@ void print_error(const char *filename, int err) {
bool wxFfmpegMediaEncoder::BeginEncode(const wxString& fileName, VideoFormat videoFormat, AudioFormat audioFormat,
AspectRatio aspectRatio, int videoBitrate, bool cbr) {
EndEncode();
+ if (videoFormat == vfNONE) {
+ AVCodecID codecId = audioFormat == afAC3 ? AV_CODEC_ID_AC3 : AV_CODEC_ID_MP2;
+ if (!addAudioStream(codecId))
+ return false;
+
+ m_audioFile = fopen((const char*) fileName.ToUTF8(), "wb");
+ if (!m_audioFile) {
+ wxLogError("Could not open '%s'", fileName.c_str());
+ return false;
+ }
+ return true;
+ }
AVOutputFormat* outputFormat = NULL;
if (videoFormat == vfNONE || audioFormat == afNONE)
outputFormat = av_guess_format(NULL, (const char*) fileName.ToUTF8(), NULL);
@@ -136,7 +148,6 @@ AVFrame* allocPicture(AVPixelFormat pix_fmt, int width, int height) {
AVFrame* frame = av_frame_alloc();
if (!frame)
return NULL;
-#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(53, 0, 0)
frame->width = width;
frame->height = height;
frame->format = pix_fmt;
@@ -144,15 +155,6 @@ AVFrame* allocPicture(AVPixelFormat pix_fmt, int width, int height) {
av_free(frame);
return NULL;
}
-#else
- int size = avpicture_get_size(pix_fmt, width, height);
- uint8_t* picture_buf = (uint8_t*) av_malloc(size);
- if (!picture_buf) {
- av_free(frame);
- return NULL;
- }
- avpicture_fill((AVPicture *) frame, picture_buf, pix_fmt, width, height);
-#endif
return frame;
}
@@ -252,25 +254,21 @@ bool wxFfmpegMediaEncoder::addAudioStream(int codecId) {
m_audioStm = NULL;
return true;
}
- m_audioStm = avformat_new_stream(m_outputCtx, NULL);
- if (!m_audioStm) {
- wxLogError(wxT("Could not alloc stream"));
- return false;
+ if (m_outputCtx != NULL) {
+ m_audioStm = avformat_new_stream(m_outputCtx, NULL);
+ if (!m_audioStm) {
+ wxLogError(wxT("Could not alloc stream"));
+ return false;
+ }
+ m_audioStm->id = 1;
}
- m_audioStm->id = 1;
// find the audio encoder and open it
AVCodec* encoder = NULL;
AVSampleFormat sampleFmt = AV_SAMPLE_FMT_S16;
if ((AVCodecID) codecId == AV_CODEC_ID_AC3) {
- // There are 2 ac3 encoders (float and integer). Depending on libav implementation/version/fork,
- // one or the other may work. So we try both.
- encoder = avcodec_find_encoder_by_name("ac3_fixed");
- if (!hasSampleFmt(encoder, sampleFmt)) {
- // Try the encoding from float format
- sampleFmt = AV_SAMPLE_FMT_FLTP;
- encoder = avcodec_find_encoder((AVCodecID) codecId );
- }
+ sampleFmt = AV_SAMPLE_FMT_FLTP;
+ encoder = avcodec_find_encoder((AVCodecID) codecId );
} else {
sampleFmt = AV_SAMPLE_FMT_S16;
encoder = avcodec_find_encoder((AVCodecID) codecId );
@@ -285,54 +283,52 @@ bool wxFfmpegMediaEncoder::addAudioStream(int codecId) {
AVCodecContext* c = m_audioCodec;
c->thread_count = m_threadCount;
- c->codec_id = (AVCodecID) codecId;
- c->codec_type = AVMEDIA_TYPE_AUDIO;
c->bit_rate = 64000;
c->sample_rate = 48000;
c->sample_fmt = sampleFmt;
c->channels = 2;
c->channel_layout = AV_CH_LAYOUT_STEREO;
- c->time_base = (AVRational){ 1, c->sample_rate };
- // some formats want stream headers to be separate
- if(m_outputCtx->oformat->flags & AVFMT_GLOBALHEADER)
- c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
-
- m_audioStm->time_base = c->time_base;
+ if (m_audioStm && avcodec_parameters_from_context(m_audioStm->codecpar, c) < 0) {
+ wxLogError("Failed to copy encoder parameters to output audio stream");
+ return false;
+ }
if (avcodec_open2(c, encoder, NULL) < 0) {
wxLogError(wxT("Could not open audio codec"));
return false;
}
- if (avcodec_parameters_from_context(m_audioStm->codecpar, c) < 0) {
- wxLogError("Failed to copy encoder parameters to output audio stream");
+
+ m_audioFrame = av_frame_alloc();
+ if (!m_audioFrame) {
+ wxLogError("Could not allocate audio frame");
return false;
}
- m_samples = (int16_t*) av_malloc(c->frame_size * av_get_bytes_per_sample(c->sample_fmt) * c->channels);
- memset(m_samples, 0, c->frame_size * av_get_bytes_per_sample(c->sample_fmt) * c->channels);
-
- m_audioFrame = av_frame_alloc();
m_audioFrame->nb_samples = c->frame_size;
- avcodec_fill_audio_frame(m_audioFrame, c->channels, c->sample_fmt, (uint8_t *) m_samples, c->frame_size
- * av_get_bytes_per_sample(c->sample_fmt) * c->channels, 1);
+ m_audioFrame->format = c->sample_fmt;
+ m_audioFrame->channel_layout = c->channel_layout;
+
+ int ret = av_frame_get_buffer(m_audioFrame, 0); // allocate the data buffers
+ if (ret < 0) {
+ wxLogError("Could not allocate audio data buffers");
+ return false;
+ }
+ ret = av_frame_make_writable(m_audioFrame);
+ if (ret < 0)
+ return false;
+ for (int i = 0; i < c->channels; i++) {
+ uint16_t *samples = (uint16_t*)m_audioFrame->data[i];
+ memset(samples, 0, c->frame_size * av_get_bytes_per_sample(c->sample_fmt));
+ }
return true;
}
void wxFfmpegMediaEncoder::CloseAudioEncoder() {
- if (!m_audioStm)
- return;
- if (m_samples) {
- av_freep(&m_samples);
- }
- if (m_audioFrame) {
- av_frame_free(&m_audioFrame);
- }
+ av_frame_free(&m_audioFrame);
+ avcodec_free_context(&m_audioCodec);
m_audioStm = NULL;
- if (m_audioCodec != NULL) {
- avcodec_close(m_audioCodec);
- }
}
void wxFfmpegMediaEncoder::CloseVideoEncoder() {
@@ -345,10 +341,8 @@ void wxFfmpegMediaEncoder::CloseVideoEncoder() {
av_freep(&m_picture);
}
av_freep(&m_videoOutbuf);
+ avcodec_free_context(&m_videoCodec);
m_videoStm = NULL;
- if (m_videoCodec != NULL) {
- avcodec_close(m_videoCodec);
- }
}
bool wxFfmpegMediaEncoder::EncodeImage(wxImage image, int frames, AbstractProgressDialog* progressDialog) {
@@ -390,20 +384,77 @@ bool wxFfmpegMediaEncoder::EncodeImage(wxImage image, int frames, AbstractProgre
return true;
}
+int encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *output) {
+ int ret;
+
+ /* send the frame for encoding */
+ ret = avcodec_send_frame(ctx, frame);
+ if (ret < 0) {
+ wxLogError("Error sending the frame to the encoder");
+ return ret;
+ }
+
+ /* read all the available output packets (in general there may be any
+ * number of them */
+ while (ret >= 0) {
+ ret = avcodec_receive_packet(ctx, pkt);
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ return 0;
+ else if (ret < 0) {
+ wxLogError("Error encoding audio frame");
+ return ret;
+ }
+
+ fwrite(pkt->data, 1, pkt->size, output);
+ av_packet_unref(pkt);
+ }
+
+ return 0;
+}
+
bool wxFfmpegMediaEncoder::EncodeAudio(double duration, AbstractProgressDialog* progressDialog) {
- // encode audio
- while (true) {
- double audioPts = m_audioStm ? ((double) m_nextAudioPts) * m_audioCodec->time_base.num
- / m_audioCodec->time_base.den : 0.0;
- if (progressDialog->WasCanceled())
+ if (m_outputCtx != NULL) {
+ // encode audio stream
+ while (true) {
+ double audioPts = m_audioCodec ? ((double) m_nextAudioPts) * m_audioCodec->time_base.num
+ / m_audioCodec->time_base.den : 0.0;
+ if (progressDialog->WasCanceled())
+ return false;
+
+ if (!m_audioCodec || audioPts >= duration)
+ break;
+
+ // write interleaved audio and video frames
+ if (!writeAudioFrame())
+ return false;
+ }
+ } else {
+ // encode audio file
+ AVCodecContext* c = m_audioCodec;
+
+ AVPacket* pkt = av_packet_alloc();
+ if (!pkt) {
+ wxLogError("could not allocate the packet");
return false;
+ }
+
+ int64_t pts = 0;
+ while (true) {
+ double audioPts = ((double) pts) * c->time_base.num /c->time_base.den;
+ if (progressDialog->WasCanceled())
+ return false;
+ if (audioPts >= duration)
+ break;
+
+ pts += m_audioFrame->nb_samples;
+ if (encode(c, m_audioFrame, pkt, m_audioFile) < 0)
+ return false;
+ }
- if (!m_audioStm || audioPts >= duration)
- break;
+ // flush the encoder
+ encode(c, NULL, pkt, m_audioFile);
- // write interleaved audio and video frames
- if (!writeAudioFrame())
- return false;
+ av_packet_free(&pkt);
}
return true;
}
@@ -429,7 +480,6 @@ int encode(AVCodecContext *avctx, AVPacket *pkt, AVFrame *frame, int *got_packet
return ret;
}
-
bool wxFfmpegMediaEncoder::writeAudioFrame() {
AVPacket pkt = { 0 }; // data and size must be 0;
int got_packet;
@@ -495,14 +545,17 @@ bool wxFfmpegMediaEncoder::writeVideoFrame() {
}
void wxFfmpegMediaEncoder::EndEncode() {
- if (!m_outputCtx)
- return;
-
- // write the trailer
- if (m_outputCtx->nb_streams)
- av_write_trailer(m_outputCtx);
-
- CloseEncoder();
+ if (m_outputCtx) {
+ // write the trailer
+ if (m_outputCtx->nb_streams)
+ av_write_trailer(m_outputCtx);
+
+ CloseEncoder();
+ } else if (m_audioFile != NULL) {
+ fclose(m_audioFile);
+ m_audioFile = NULL;
+ CloseAudioEncoder();
+ }
}
void wxFfmpegMediaEncoder::CloseEncoder() {
diff --git a/src/mediaenc_ffmpeg.h b/src/mediaenc_ffmpeg.h
index bf4ad65..74d8210 100644
--- a/src/mediaenc_ffmpeg.h
+++ b/src/mediaenc_ffmpeg.h
@@ -48,7 +48,6 @@ private:
bool addVideoStream(int codecId, VideoFormat videoFormat, AspectRatio aspectRatio, int videoBitrate, bool cbr);
bool addAudioStream(int codecId);
- int16_t* m_samples;
AVFrame* m_audioFrame;
void CloseAudioEncoder();
@@ -57,12 +56,15 @@ private:
uint8_t* m_videoOutbuf;
void CloseVideoEncoder();
- void getAudioFrame(int nbChannels);
+ /** writes a silent audio frame */
bool writeAudioFrame();
/** writes m_picture */
bool writeVideoFrame();
void CloseEncoder();
+
+ /** used to encode audio file **/
+ FILE* m_audioFile;
};
#endif // WX_FFMPEG_MEDIA_ENCODER_H
--
2.38.0