Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Backports:SLE-15-SP4:FactoryCandidates
DVDStyler
0001-fixed-encoding-of-silent-audio-file.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
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
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor