1 /**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 AVCodecContextWrapper.cpp
6
7 Dmitry Vedenko
8
9 **********************************************************************/
10
11 #include "AVCodecContextWrapper.h"
12
13 #include <cstring>
14
15 #include "FFmpegFunctions.h"
16 #include "AVCodecWrapper.h"
17
AVCodecContextWrapper(const FFmpegFunctions & ffmpeg,std::unique_ptr<AVCodecWrapper> codec)18 AVCodecContextWrapper::AVCodecContextWrapper(
19 const FFmpegFunctions& ffmpeg, std::unique_ptr<AVCodecWrapper> codec) noexcept
20 : mFFmpeg(ffmpeg)
21 , mAVCodec(std::move(codec))
22 , mIsOwned(true)
23 {
24 mAVCodecContext =
25 mFFmpeg.avcodec_alloc_context3(mAVCodec->GetWrappedValue());
26 }
27
AVCodecContextWrapper(const FFmpegFunctions & ffmpeg,AVCodecContext * wrapped)28 AVCodecContextWrapper::AVCodecContextWrapper(
29 const FFmpegFunctions& ffmpeg, AVCodecContext* wrapped) noexcept
30 : mFFmpeg(ffmpeg)
31 , mAVCodecContext(wrapped)
32 , mIsOwned(false)
33 {
34
35 }
36
GetWrappedValue()37 AVCodecContext* AVCodecContextWrapper::GetWrappedValue() noexcept
38 {
39 return mAVCodecContext;
40 }
41
GetWrappedValue() const42 const AVCodecContext* AVCodecContextWrapper::GetWrappedValue() const noexcept
43 {
44 return mAVCodecContext;
45 }
46
~AVCodecContextWrapper()47 AVCodecContextWrapper::~AVCodecContextWrapper()
48 {
49 if (mIsOwned && mAVCodecContext != nullptr)
50 {
51 // avcodec_free_context, complementary to avcodec_alloc_context3, is
52 // not necessarily loaded
53 if (mFFmpeg.avcodec_free_context != nullptr)
54 {
55 mFFmpeg.avcodec_free_context(&mAVCodecContext);
56 }
57 else
58 {
59 // Its not clear how to avoid the leak here, but let's close
60 // the codec at least
61 if (mFFmpeg.avcodec_is_open(mAVCodecContext))
62 mFFmpeg.avcodec_close(mAVCodecContext);
63 }
64 }
65 }
66
67 std::vector<uint8_t>
DecodeAudioPacket(const AVPacketWrapper * packet)68 AVCodecContextWrapper::DecodeAudioPacket(const AVPacketWrapper* packet)
69 {
70 auto frame = mFFmpeg.CreateAVFrameWrapper();
71 std::vector<uint8_t> data;
72
73 if (mFFmpeg.avcodec_decode_audio4)
74 {
75 std::unique_ptr<AVPacketWrapper> packetCopy =
76 packet ? packet->Clone() : mFFmpeg.CreateAVPacketWrapper();
77
78 /*
79 "Flushing is done by calling this function [avcodec_decode_audio4]
80 with packets with avpkt->data set to NULL and avpkt->size set to 0
81 until it stops returning samples."
82 (That implies, not necessarily just one loop pass to flush)
83 */
84 bool flushing = packet
85 ? (packetCopy->GetSize() == 0 && packetCopy->GetData() == nullptr)
86 : true;
87 if (!flushing && packetCopy->GetData() == nullptr)
88 return {};
89
90 const int channels = GetChannels();
91
92 int bytesDecoded = 0;
93 do
94 {
95 int gotFrame;
96 // Deprecated? https://ffmpeg.org/doxygen/3.3/group__lavc__decoding.html#gaaa1fbe477c04455cdc7a994090100db4
97 bytesDecoded = mFFmpeg.avcodec_decode_audio4(
98 mAVCodecContext, frame->GetWrappedValue(), &gotFrame,
99 packetCopy->GetWrappedValue());
100
101 if (bytesDecoded < 0)
102 return data; // Packet decoding has failed
103
104 if (gotFrame == 0)
105 {
106 /*
107 "Note that this field being set to zero does not mean that an
108 error has occurred. For decoders with AV_CODEC_CAP_DELAY set, no
109 given decode call is guaranteed to produce a frame."
110 */
111 // (Let's assume this doesn't happen when flushing)
112 // Still, the data was consumed by the decoder, so we need to
113 // offset the packet
114 packetCopy->OffsetPacket(bytesDecoded);
115 continue;
116 }
117
118 const auto sampleSize =
119 static_cast<size_t>(mFFmpeg.av_get_bytes_per_sample(
120 static_cast<AVSampleFormatFwd>(frame->GetFormat())));
121
122 const auto samplesCount = frame->GetSamplesCount();
123 const auto frameSize = channels * sampleSize * samplesCount;
124
125 auto oldSize = data.size();
126 data.resize(oldSize + frameSize);
127 auto pData = &data[oldSize];
128
129 if (frame->GetData(1) != nullptr)
130 {
131 // We return interleaved buffer
132 for (int channel = 0; channel < channels; channel++)
133 {
134 for (int sample = 0; sample < samplesCount; sample++)
135 {
136 const uint8_t* channelData =
137 frame->GetExtendedData(channel) + sampleSize * sample;
138
139 uint8_t* output =
140 pData + sampleSize * (channels * sample + channel);
141
142 std::copy(channelData, channelData + sampleSize, output);
143 }
144 }
145 }
146 else
147 {
148 uint8_t* frameData = frame->GetData(0);
149 std::copy(frameData, frameData + frameSize, pData);
150 }
151
152 packetCopy->OffsetPacket(bytesDecoded);
153 }
154 while ( flushing ? bytesDecoded > 0 : packetCopy->GetSize() > 0 );
155 }
156
157 return data;
158 }
159
160 namespace
161 {
MakeTag(char a,char b,char c,char d)162 unsigned int MakeTag(char a, char b, char c, char d) noexcept
163 {
164 return
165 (static_cast<unsigned>(a) << 0) | (static_cast<unsigned>(b) << 8) |
166 (static_cast<unsigned>(c) << 16) | (static_cast<unsigned>(d) << 24);
167 }
168 }
169
SetCodecTagFourCC(const char * fourCC)170 void AVCodecContextWrapper::SetCodecTagFourCC(const char* fourCC) noexcept
171 {
172 if (fourCC == nullptr || std::strlen(fourCC) != 4)
173 return;
174
175 SetCodecTag(MakeTag(fourCC[0], fourCC[1], fourCC[2], fourCC[3]));
176 }
177