AvTranscoder  0.9.4
C++APIforLibav/FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AudioDecoder.cpp
Go to the documentation of this file.
1 #include "AudioDecoder.hpp"
2 
6 
7 extern "C" {
8 #include <libavcodec/avcodec.h>
9 #include <libavformat/avformat.h>
10 #include <libavutil/avutil.h>
11 #include <libavutil/pixdesc.h>
12 #include <libavutil/channel_layout.h>
13 }
14 
15 #include <stdexcept>
16 #include <sstream>
17 
18 namespace avtranscoder
19 {
20 
22  : _inputStream(&inputStream)
23  , _isSetup(false)
24 {
25 }
26 
28 {
29 }
30 
32 {
33  // check the given profile
34  const bool isValid = ProfileLoader::checkAudioProfile(profile);
35  if(!isValid && !profile.empty())
36  {
37  const std::string msg("Invalid audio profile to setup decoder.");
38  LOG_ERROR(msg)
39  throw std::runtime_error(msg);
40  }
41 
42  if(!profile.empty())
43  {
44  LOG_INFO("Setup audio decoder with:\n" << profile)
45  }
46 
48 
49  // set threads before any other options
50  if(profile.count(constants::avProfileThreads))
52  else
54 
55  // set decoder options
56  for(ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it)
57  {
59  (*it).first == constants::avProfileType || (*it).first == constants::avProfileThreads)
60  continue;
61 
62  try
63  {
64  Option& decodeOption = codec.getOption((*it).first);
65  decodeOption.setString((*it).second);
66  }
67  catch(std::exception& e)
68  {
69  LOG_WARN("AudioDecoder - can't set option " << (*it).first << " to " << (*it).second << ": " << e.what())
70  }
71  }
72 
73  // open decoder
75  _isSetup = true;
76 }
77 
79 {
80  bool decodeNextFrame = false;
81 
82  if(!_isSetup)
83  setupDecoder();
84 
85  int got_frame = 0;
86  while(!got_frame)
87  {
88  CodedData data;
89 
90  // reading
91  const bool nextPacketRead = _inputStream->readNextPacket(data);
92 
93  // decoding
94  // @note could be called several times to return the remaining frames (last call with an empty packet)
95  // @see CODEC_CAP_DELAY
96  int ret = avcodec_decode_audio4(&_inputStream->getAudioCodec().getAVCodecContext(), &frameBuffer.getAVFrame(),
97  &got_frame, &data.getAVPacket());
98  if(ret < 0)
99  {
100  throw std::runtime_error("an error occured during audio decoding" + getDescriptionFromErrorCode(ret));
101  }
102 
103  // if no frame could be decompressed
104  if(!nextPacketRead && ret == 0 && got_frame == 0)
105  decodeNextFrame = false;
106  else
107  decodeNextFrame = true;
108 
109  // if no frame read and decompressed
110  if(!nextPacketRead && !decodeNextFrame)
111  {
112  data.clear();
113  return false;
114  }
115  }
116  return decodeNextFrame;
117 }
118 
119 bool AudioDecoder::decodeNextFrame(Frame& frameBuffer, const size_t channelIndex)
120 {
121  AudioFrame& audioBuffer = static_cast<AudioFrame&>(frameBuffer);
122 
123  // decode all data of the next frame
124  AudioFrame allDataOfNextFrame(audioBuffer);
125  if(!decodeNextFrame(allDataOfNextFrame))
126  return false;
127 
128  AVCodecContext& avCodecContext = _inputStream->getAudioCodec().getAVCodecContext();
129  const size_t srcNbChannels = avCodecContext.channels;
130  const size_t bytePerSample = av_get_bytes_per_sample((AVSampleFormat)frameBuffer.getAVFrame().format);
131 
132  const int dstNbChannels = 1;
133  const int noAlignment = 0;
134  const size_t decodedSize = av_samples_get_buffer_size(NULL, dstNbChannels, frameBuffer.getAVFrame().nb_samples,
135  avCodecContext.sample_fmt, noAlignment);
136  if(decodedSize == 0)
137  return false;
138 
139  // check if the expected channel exists
140  if(channelIndex > srcNbChannels - 1)
141  {
142  std::stringstream msg;
143  msg << "The channel at index ";
144  msg << channelIndex;
145  msg << " doesn't exist (srcNbChannels = ";
146  msg << srcNbChannels;
147  msg << ").";
148  throw std::runtime_error(msg.str());
149  }
150 
151  // copy frame properties of decoded frame
152  audioBuffer.copyProperties(allDataOfNextFrame);
153  av_frame_set_channels(&audioBuffer.getAVFrame(), 1);
154  av_frame_set_channel_layout(&audioBuffer.getAVFrame(), AV_CH_LAYOUT_MONO);
155  audioBuffer.setNbSamplesPerChannel(allDataOfNextFrame.getNbSamplesPerChannel());
156 
157  // @todo manage cases with data of frame not only on data[0] (use _frame.linesize)
158  unsigned char* src = allDataOfNextFrame.getData()[0];
159  unsigned char* dst = audioBuffer.getData()[0];
160 
161  // offset
162  src += channelIndex * bytePerSample;
163 
164  // extract one channel
165  for(int sample = 0; sample < allDataOfNextFrame.getAVFrame().nb_samples; ++sample)
166  {
167  memcpy(dst, src, bytePerSample);
168  dst += bytePerSample;
169  src += bytePerSample * srcNbChannels;
170  }
171 
172  return true;
173 }
174 
176 {
177  avcodec_flush_buffers(&_inputStream->getAudioCodec().getAVCodecContext());
178 }
179 }
bool readNextPacket(CodedData &data)
Read the next packet of the stream.
Definition: InputStream.cpp:53
AudioCodec & getAudioCodec()
Definition: InputStream.cpp:87
void setString(const std::string &value)
Definition: Option.cpp:187
#define LOG_ERROR(...)
Definition: log.hpp:35
void setupDecoder(const ProfileLoader::Profile &profile=ProfileLoader::Profile())
Setup the decoder.
void clear()
Clear existing data and set size to 0.
Definition: CodedData.cpp:71
void setInt(const int value)
Definition: Option.cpp:169
void flushDecoder()
Reset the internal decoder state / flush internal buffers.
std::string getDescriptionFromErrorCode(const int code)
Get the string description corresponding to the error code provided by ffmpeg/libav.
Definition: common.cpp:22
AVPacket & getAVPacket()
Definition: CodedData.hpp:78
std::map< std::string, std::string > Profile
const std::string avProfileIdentificator
const std::string avProfileIdentificatorHuman
void setNbSamplesPerChannel(const size_t nbSamples)
Definition: AudioFrame.hpp:54
#define LOG_INFO(...)
Definition: log.hpp:23
Option & getOption(const std::string &optionName)
Definition: ICodec.hpp:50
InputStream * _inputStream
Stream from which we read next frames (no ownership, has link)
void copyProperties(const Frame &otherFrame)
Copy all the fields that do not affect the data layout in the buffers.
Definition: Frame.cpp:57
Wrapper of AVOption. Get its type to know what the option is about: Int, Double, Ratio, Choice... Parse its array of options to get the potential childs (Choice and Group).
Definition: Option.hpp:36
unsigned char ** getData()
Get all the data of the frame.
Definition: Frame.hpp:35
#define LOG_WARN(...)
Definition: log.hpp:29
AudioDecoder(InputStream &inputStream)
static bool checkAudioProfile(const Profile &profileToCheck)
This class describes decoded audio data.
Definition: AudioFrame.hpp:36
This class describes decoded (raw) audio or video data.
Definition: Frame.hpp:16
void openCodec()
Initialize the codec context.
Definition: ICodec.cpp:56
bool decodeNextFrame(Frame &frameBuffer)
Decode next frame.
AVCodecContext & getAVCodecContext()
Definition: ICodec.hpp:53
This class describes coded data.
Definition: CodedData.hpp:18
const std::string avProfileThreads
AVFrame & getAVFrame()
Definition: Frame.hpp:88
size_t getNbSamplesPerChannel() const
Definition: AudioFrame.hpp:49
const std::string avProfileType
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy