AvTranscoder  0.9.4
C++APIforLibav/FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OutputFile.cpp
Go to the documentation of this file.
1 #include "OutputFile.hpp"
2 
3 #include <AvTranscoder/util.hpp>
4 
5 #include <stdexcept>
6 
7 #ifndef FF_INPUT_BUFFER_PADDING_SIZE
8 #define FF_INPUT_BUFFER_PADDING_SIZE 16
9 #endif
10 
11 namespace avtranscoder
12 {
13 
14 OutputFile::OutputFile(const std::string& filename, const std::string& formatName, const std::string& mimeType)
15  : _formatContext(AV_OPT_FLAG_ENCODING_PARAM)
16  , _outputStreams()
17  , _frameCount()
18  , _previousProcessedStreamDuration(0.0)
19  , _profile()
20 {
21  _formatContext.setFilename(filename);
22  _formatContext.setOutputFormat(filename, formatName, mimeType);
23 }
24 
26 {
27  for(std::vector<OutputStream*>::iterator it = _outputStreams.begin(); it != _outputStreams.end(); ++it)
28  {
29  delete(*it);
30  }
31 }
32 
34 {
35  AVStream& stream = _formatContext.addAVStream(videoDesc.getAVCodec());
36 
37  stream.codec->width = videoDesc.getAVCodecContext().width;
38  stream.codec->height = videoDesc.getAVCodecContext().height;
39  stream.codec->bit_rate = videoDesc.getAVCodecContext().bit_rate;
40  stream.codec->pix_fmt = videoDesc.getAVCodecContext().pix_fmt;
41  stream.codec->profile = videoDesc.getAVCodecContext().profile;
42  stream.codec->level = videoDesc.getAVCodecContext().level;
43  stream.codec->field_order = videoDesc.getAVCodecContext().field_order;
44 
45  // some codecs need/can use extradata to decode
46  uint8_t* srcExtradata = videoDesc.getAVCodecContext().extradata;
47  const int srcExtradataSize = videoDesc.getAVCodecContext().extradata_size;
48  stream.codec->extradata = (uint8_t*)av_malloc(srcExtradataSize + FF_INPUT_BUFFER_PADDING_SIZE);
49  memcpy(stream.codec->extradata, srcExtradata, srcExtradataSize);
50  memset(((uint8_t*)stream.codec->extradata) + srcExtradataSize, 0, FF_INPUT_BUFFER_PADDING_SIZE);
51  stream.codec->extradata_size = videoDesc.getAVCodecContext().extradata_size;
52 
53  // need to set the time_base on the AVCodecContext and the AVStream
54  // compensating the frame rate with the ticks_per_frame and keeping
55  // a coherent reading speed.
56  av_reduce(&stream.codec->time_base.num, &stream.codec->time_base.den,
57  videoDesc.getAVCodecContext().time_base.num * videoDesc.getAVCodecContext().ticks_per_frame,
58  videoDesc.getAVCodecContext().time_base.den, INT_MAX);
59 
60  stream.time_base = stream.codec->time_base;
61 
62  OutputStream* outputStream = new OutputStream(*this, _formatContext.getNbStreams() - 1);
63  _outputStreams.push_back(outputStream);
64 
65  return *outputStream;
66 }
67 
69 {
70  AVStream& stream = _formatContext.addAVStream(audioDesc.getAVCodec());
71 
72  stream.codec->sample_rate = audioDesc.getAVCodecContext().sample_rate;
73  stream.codec->channels = audioDesc.getAVCodecContext().channels;
74  stream.codec->channel_layout = audioDesc.getAVCodecContext().channel_layout;
75  stream.codec->sample_fmt = audioDesc.getAVCodecContext().sample_fmt;
76  stream.codec->frame_size = audioDesc.getAVCodecContext().frame_size;
77 
78  // need to set the time_base on the AVCodecContext of the AVStream
79  av_reduce(&stream.codec->time_base.num, &stream.codec->time_base.den, audioDesc.getAVCodecContext().time_base.num,
80  audioDesc.getAVCodecContext().time_base.den, INT_MAX);
81 
82  OutputStream* outputStream = new OutputStream(*this, _formatContext.getNbStreams() - 1);
83  _outputStreams.push_back(outputStream);
84 
85  return *outputStream;
86 }
87 
89 {
91 
92  OutputStream* outputStream = new OutputStream(*this, _formatContext.getNbStreams() - 1);
93  _outputStreams.push_back(outputStream);
94 
95  return *outputStream;
96 }
97 
98 IOutputStream& OutputFile::getStream(const size_t streamIndex)
99 {
100  if(streamIndex >= _outputStreams.size())
101  {
102  std::stringstream msg;
103  msg << "Unable to get the stream ";
104  msg << streamIndex;
105  msg << ": the OutputFile '";
106  msg << getFilename();
107  msg << "' has only ";
108  msg << _outputStreams.size();
109  msg << " streams.";
110  throw std::runtime_error(msg.str());
111  }
112  return *_outputStreams.at(streamIndex);
113 }
114 
115 std::string OutputFile::getFilename() const
116 {
117  return std::string(_formatContext.getAVFormatContext().filename);
118 }
119 
120 std::string OutputFile::getFormatName() const
121 {
122  if(_formatContext.getAVOutputFormat().name == NULL)
123  {
124  LOG_WARN("Unknown muxer format name of '" << getFilename() << "'.")
125  return "";
126  }
127  return std::string(_formatContext.getAVOutputFormat().name);
128 }
129 
130 std::string OutputFile::getFormatLongName() const
131 {
132  if(_formatContext.getAVOutputFormat().long_name == NULL)
133  {
134  LOG_WARN("Unknown muxer format long name of '" << getFilename() << "'.")
135  return "";
136  }
137  return std::string(_formatContext.getAVOutputFormat().long_name);
138 }
139 
140 std::string OutputFile::getFormatMimeType() const
141 {
142  if(_formatContext.getAVOutputFormat().mime_type == NULL)
143  {
144  LOG_WARN("Unknown muxer format mime type of '" << getFilename() << "'.")
145  return "";
146  }
147  return std::string(_formatContext.getAVOutputFormat().mime_type);
148 }
149 
151 {
152  LOG_DEBUG("Begin wrap of OutputFile")
153 
154  _formatContext.openRessource(getFilename(), AVIO_FLAG_WRITE);
156 
157  // set specific wrapping options
159 
160  _frameCount.clear();
161  _frameCount.resize(_outputStreams.size(), 0);
162 
163  return true;
164 }
165 
166 IOutputStream::EWrappingStatus OutputFile::wrap(const CodedData& data, const size_t streamIndex)
167 {
168  if(!data.getSize())
170 
171  LOG_DEBUG("Wrap on stream " << streamIndex << " (" << data.getSize() << " bytes for frame "
172  << _frameCount.at(streamIndex) << ")")
173 
174  // Packet to wrap
175  AVPacket packet;
176  av_init_packet(&packet);
177  packet.stream_index = streamIndex;
178  packet.data = (uint8_t*)data.getData();
179  packet.size = data.getSize();
180  packet.flags = data.getAVPacket().flags;
181 
182  // copy timing information
183  if(!_outputStreams.at(streamIndex)->isPTSGenerated())
184  {
185  if(data.getAVStream() != NULL)
186  {
187  const AVRational& srcTimeBase = data.getAVStream()->time_base;
188  const AVRational& dstTimeBase = _formatContext.getAVStream(streamIndex).time_base;
189  // duration
190  packet.duration = av_rescale_q(data.getAVPacket().duration, srcTimeBase, dstTimeBase);
191  // pts
192  if(data.getAVPacket().pts != AV_NOPTS_VALUE)
193  packet.pts = av_rescale_q(data.getAVPacket().pts, srcTimeBase, dstTimeBase);
194  else
195  packet.pts = AV_NOPTS_VALUE;
196  // dts
197  packet.dts = av_rescale_q(data.getAVPacket().dts, srcTimeBase, dstTimeBase);
198  }
199  // add stream PTS if already incremented
200  const int currentStreamPTS = _outputStreams.at(streamIndex)->getStreamPTS();
201  if(packet.pts != AV_NOPTS_VALUE && packet.pts < currentStreamPTS)
202  {
203  packet.pts += currentStreamPTS;
204  packet.dts += currentStreamPTS;
205  }
206  }
207 
208  // copy duration of packet wrapped
209  // @see OutputStream
210  const_cast<CodedData&>(data).getAVPacket().duration = packet.duration;
211 
212  // Write packet
213  _formatContext.writeFrame(packet);
214 
215  const double currentStreamDuration = _outputStreams.at(streamIndex)->getStreamDuration();
216  if(currentStreamDuration < _previousProcessedStreamDuration)
217  {
218  LOG_DEBUG("The output stream " << streamIndex << " is strictly shorter than the previous duration saved ("
219  << currentStreamDuration << "s < " << _previousProcessedStreamDuration
220  << "s): wait for more data.")
222  }
223 
224  _previousProcessedStreamDuration = currentStreamDuration;
225  _frameCount.at(streamIndex)++;
226 
228 }
229 
231 {
232  LOG_DEBUG("End wrap of OutputFile")
233 
236  return true;
237 }
238 
240 {
241  for(PropertyVector::const_iterator it = data.begin(); it != data.end(); ++it)
242  {
243  addMetadata(it->first, it->second);
244  }
245 }
246 
247 void OutputFile::addMetadata(const std::string& key, const std::string& value)
248 {
249  _formatContext.addMetaData(key, value);
250 }
251 
253 {
254  // check the given profile
255  const bool isValid = ProfileLoader::checkFormatProfile(profile);
256  if(!isValid)
257  {
258  const std::string msg("Invalid format profile to setup wrapping.");
259  LOG_ERROR(msg)
260  throw std::runtime_error(msg);
261  }
262 
263  if(!profile.empty())
264  {
265  LOG_INFO("Setup wrapping with:\n" << profile)
266  }
267 
268  // check if output format indicated is valid with the filename extension
269  if(!av_guess_format(profile.find(constants::avProfileFormat)->second.c_str(), getFilename().c_str(), NULL))
270  {
271  throw std::runtime_error("Invalid format according to the file extension.");
272  }
273  // set output format
275 
276  // set common wrapping options
277  setupWrappingOptions(profile);
278 }
279 
281 {
282  // set format options
283  for(ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it)
284  {
286  (*it).first == constants::avProfileType || (*it).first == constants::avProfileFormat)
287  continue;
288 
289  try
290  {
291  Option& formatOption = _formatContext.getOption((*it).first);
292  formatOption.setString((*it).second);
293  }
294  catch(std::exception& e)
295  {
296  LOG_INFO("OutputFile - option " << (*it).first << " will be saved to be called when beginWrap")
297  _profile[(*it).first] = (*it).second;
298  }
299  }
300 }
301 
303 {
304  // set format options
305  for(ProfileLoader::Profile::const_iterator it = _profile.begin(); it != _profile.end(); ++it)
306  {
308  (*it).first == constants::avProfileType || (*it).first == constants::avProfileFormat)
309  continue;
310 
311  try
312  {
313  Option& formatOption = _formatContext.getOption((*it).first);
314  formatOption.setString((*it).second);
315  }
316  catch(std::exception& e)
317  {
318  LOG_WARN("OutputFile - can't set option " << (*it).first << " to " << (*it).second << ": " << e.what())
319  }
320  }
321 }
322 }
double _previousProcessedStreamDuration
To manage process streams order.
Definition: OutputFile.hpp:106
FormatContext _formatContext
Definition: OutputFile.hpp:102
std::vector< std::pair< std::string, std::string > > PropertyVector
PropertyVector is a vector of pair, because the order of properties matters to us.
Definition: util.hpp:23
void setString(const std::string &value)
Definition: Option.cpp:187
void setupWrapping(const ProfileLoader::Profile &profile)
Set the format and the generic options of the output file.
Definition: OutputFile.cpp:252
#define LOG_ERROR(...)
Definition: log.hpp:35
unsigned char * getData()
Definition: CodedData.hpp:65
void closeRessource()
Close the resource accessed by the AVIOContext and free it.
static bool checkFormatProfile(const Profile &profileToCheck)
const std::string avProfileFormat
std::string getFormatName() const
A comma separated list of short names for the format, or empty if unknown.
Definition: OutputFile.cpp:120
void setOutputFormat(const std::string &filename, const std::string &shortName="", const std::string &mimeType="")
AVOutputFormat & getAVOutputFormat() const
void addMetaData(const std::string &key, const std::string &value)
std::string getFormatMimeType() const
Comma-separated list of mime types, or empty if unknown.
Definition: OutputFile.cpp:140
EWrappingStatus
define wrapping result status
const AVStream * getAVStream() const
Definition: CodedData.hpp:77
AVPacket & getAVPacket()
Definition: CodedData.hpp:78
std::map< std::string, std::string > Profile
const std::string avProfileIdentificator
std::string getFilename() const
Definition: OutputFile.cpp:115
const std::string avProfileIdentificatorHuman
ProfileLoader::Profile _profile
To setup specific wrapping options.
Definition: OutputFile.hpp:113
IOutputStream & addAudioStream(const AudioCodec &audioDesc)
Add an audio output stream.
Definition: OutputFile.cpp:68
AVStream & addAVStream(const AVCodec &avCodec)
#define LOG_INFO(...)
Definition: log.hpp:23
void setupWrappingOptions(const ProfileLoader::Profile &profile)
Definition: OutputFile.cpp:280
void writeTrailer()
Write the stream trailer to an output media file.
void writeHeader(AVDictionary **options=NULL)
Write the stream header to an output media file.
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
IOutputStream::EWrappingStatus wrap(const CodedData &data, const size_t streamIndex)
Wrap a packet of data in the output ressource.
Definition: OutputFile.cpp:166
Option & getOption(const std::string &optionName)
std::string getFormatLongName() const
Descriptive name for the format, meant to be more human-readable than name, or empty if unknown...
Definition: OutputFile.cpp:130
#define LOG_WARN(...)
Definition: log.hpp:29
std::vector< size_t > _frameCount
Number of wrapped frames.
Definition: OutputFile.hpp:104
OutputFile(const OutputFile &outputFile)
bool endWrap()
Close ressource and write trailer.
Definition: OutputFile.cpp:230
size_t getSize() const
Definition: CodedData.hpp:70
void writeFrame(AVPacket &packet, bool interleaved=true)
Write a packet to an output media file.
bool beginWrap()
Open ressource, write header, and setup specific wrapping options given when call setupWrapping...
Definition: OutputFile.cpp:150
AVCodecContext & getAVCodecContext()
Definition: ICodec.hpp:53
#define LOG_DEBUG(...)
Definition: log.hpp:17
This class describes coded data.
Definition: CodedData.hpp:18
void addMetadata(const PropertyVector &data)
Add metadata to the output file.
Definition: OutputFile.cpp:239
void openRessource(const std::string &url, int flags)
Create and initialize a AVIOContext for accessing the resource indicated by url.
#define FF_INPUT_BUFFER_PADDING_SIZE
Definition: OutputFile.cpp:8
AVCodec & getAVCodec()
Definition: ICodec.hpp:55
AVFormatContext & getAVFormatContext() const
IOutputStream & getStream(const size_t streamIndex)
Get the output stream.
Definition: OutputFile.cpp:98
std::vector< OutputStream * > _outputStreams
Has ownership.
Definition: OutputFile.hpp:103
const std::string avProfileType
IOutputStream & addDataStream(const DataCodec &dataDesc)
Add a data output stream.
Definition: OutputFile.cpp:88
AVStream & getAVStream(size_t index) const
IOutputStream & addVideoStream(const VideoCodec &videoDesc)
Add a video output stream.
Definition: OutputFile.cpp:33
void setFilename(const std::string &filename)
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