AvTranscoder  0.9.4
C++APIforLibav/FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
StreamTranscoder.cpp
Go to the documentation of this file.
1 
2 #include "StreamTranscoder.hpp"
3 
5 
12 
15 
16 #include <cassert>
17 #include <limits>
18 #include <sstream>
19 
20 namespace avtranscoder
21 {
22 
23 StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outputFile, const float offset)
24  : _inputStream(&inputStream)
25  , _outputStream(NULL)
26  , _sourceBuffer(NULL)
27  , _frameBuffer(NULL)
28  , _inputDecoder(NULL)
29  , _generator(NULL)
30  , _currentDecoder(NULL)
31  , _outputEncoder(NULL)
32  , _transform(NULL)
33  , _filterGraph(NULL)
34  , _subStreamIndex(-1)
35  , _offset(offset)
36  , _needToSwitchToGenerator(false)
37 {
38  // create a re-wrapping case
40  {
41  case AVMEDIA_TYPE_VIDEO:
42  {
43  // output stream
45 
46  try
47  {
48  // filter
50 
52 
53  // generator decoder
54  _generator = new VideoGenerator(inputFrameDesc);
55 
56  // buffers to process
57  _sourceBuffer = new VideoFrame(inputFrameDesc);
58  _frameBuffer = new VideoFrame(inputFrameDesc);
59 
60  // transform
61  _transform = new VideoTransform();
62 
63  // output encoder
65  outputVideo->setupVideoEncoder(inputFrameDesc);
66  _outputEncoder = outputVideo;
67  }
68  catch(std::runtime_error& e)
69  {
70  LOG_WARN("Cannot create the video encoder for stream " << _inputStream->getStreamIndex() << " if needed. "
71  << e.what())
72  }
73 
74  break;
75  }
76  case AVMEDIA_TYPE_AUDIO:
77  {
78  // output stream
80 
81  try
82  {
83  // filter
85 
87 
88  // generator decoder
89  _generator = new AudioGenerator(inputFrameDesc);
90 
91  // buffers to process
92  _sourceBuffer = new AudioFrame(inputFrameDesc);
93  _frameBuffer = new AudioFrame(inputFrameDesc);
94 
95  // transform
96  _transform = new AudioTransform();
97 
98  // output encoder
100  outputAudio->setupAudioEncoder(inputFrameDesc);
101  _outputEncoder = outputAudio;
102  }
103 
104  catch(std::runtime_error& e)
105  {
106  LOG_WARN("Cannot create the audio encoder for stream " << _inputStream->getStreamIndex() << " if needed. "
107  << e.what())
108  }
109 
110  break;
111  }
112  case AVMEDIA_TYPE_DATA:
113  {
114  // @warning: rewrap a data stream can't be lengthen by a generator (end of rewrapping will end the all process)
116  break;
117  }
118  default:
119  break;
120  }
121  setOffset(offset);
122 }
123 
125  const int subStreamIndex, const float offset)
126  : _inputStream(&inputStream)
127  , _outputStream(NULL)
128  , _sourceBuffer(NULL)
129  , _frameBuffer(NULL)
130  , _inputDecoder(NULL)
131  , _generator(NULL)
132  , _currentDecoder(NULL)
133  , _outputEncoder(NULL)
134  , _transform(NULL)
135  , _filterGraph(NULL)
136  , _subStreamIndex(subStreamIndex)
137  , _offset(offset)
138  , _needToSwitchToGenerator(false)
139 {
140  // create a transcode case
142  {
143  case AVMEDIA_TYPE_VIDEO:
144  {
145  // filter
147 
148  // input decoder
149  VideoDecoder* inputVideo = new VideoDecoder(*static_cast<InputStream*>(_inputStream));
150  inputVideo->setupDecoder();
151  _inputDecoder = inputVideo;
153 
154  // output encoder
155  VideoEncoder* outputVideo = new VideoEncoder(profile.at(constants::avProfileCodec));
156  _outputEncoder = outputVideo;
157 
159  outputFrameDesc.setParameters(profile);
160  outputVideo->setupVideoEncoder(outputFrameDesc, profile);
161 
162  // output stream
163  _outputStream = &outputFile.addVideoStream(outputVideo->getVideoCodec());
164 
165  // buffers to process
167  _frameBuffer = new VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc());
168 
169  // transform
170  _transform = new VideoTransform();
171 
172  // generator decoder
174 
175  break;
176  }
177  case AVMEDIA_TYPE_AUDIO:
178  {
179  // filter
181 
182  // input decoder
183  AudioDecoder* inputAudio = new AudioDecoder(*static_cast<InputStream*>(_inputStream));
184  inputAudio->setupDecoder();
185  _inputDecoder = inputAudio;
187 
188  // output encoder
189  AudioEncoder* outputAudio = new AudioEncoder(profile.at(constants::avProfileCodec));
190  _outputEncoder = outputAudio;
191 
193  outputFrameDesc.setParameters(profile);
194  if(subStreamIndex > -1)
195  {
196  // @todo manage downmix ?
197  outputFrameDesc._nbChannels = 1;
198  }
199  outputAudio->setupAudioEncoder(outputFrameDesc, profile);
200 
201  // output stream
202  _outputStream = &outputFile.addAudioStream(outputAudio->getAudioCodec());
203 
204  // buffers to process
206  if(subStreamIndex > -1)
207  inputFrameDesc._nbChannels = 1;
208 
209  _sourceBuffer = new AudioFrame(inputFrameDesc);
210  _frameBuffer = new AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc());
211 
212  // transform
213  _transform = new AudioTransform();
214 
215  // generator decoder
216  _generator = new AudioGenerator(outputFrameDesc);
217 
218  break;
219  }
220  default:
221  {
222  throw std::runtime_error("unupported stream type");
223  break;
224  }
225  }
226  setOffset(offset);
227 }
228 
229 StreamTranscoder::StreamTranscoder(const ICodec& inputCodec, IOutputFile& outputFile, const ProfileLoader::Profile& profile)
230  : _inputStream(NULL)
231  , _outputStream(NULL)
232  , _sourceBuffer(NULL)
233  , _frameBuffer(NULL)
234  , _inputDecoder(NULL)
235  , _generator(NULL)
236  , _currentDecoder(NULL)
237  , _outputEncoder(NULL)
238  , _transform(NULL)
239  , _filterGraph(NULL)
240  , _subStreamIndex(-1)
241  , _offset(0)
242  , _needToSwitchToGenerator(false)
243 {
244  if(profile.find(constants::avProfileType)->second == constants::avProfileTypeVideo)
245  {
246  const VideoCodec& inputVideoCodec = static_cast<const VideoCodec&>(inputCodec);
247  // generator decoder
248  _generator = new VideoGenerator(inputVideoCodec.getVideoFrameDesc());
250 
251  // filter
252  _filterGraph = new FilterGraph(inputVideoCodec);
253 
254  // buffers to process
255  VideoFrameDesc inputFrameDesc = inputVideoCodec.getVideoFrameDesc();
256  VideoFrameDesc outputFrameDesc = inputFrameDesc;
257  outputFrameDesc.setParameters(profile);
258  _sourceBuffer = new VideoFrame(inputFrameDesc);
259  _frameBuffer = new VideoFrame(outputFrameDesc);
260 
261  // transform
262  _transform = new VideoTransform();
263 
264  // output encoder
265  VideoEncoder* outputVideo = new VideoEncoder(profile.at(constants::avProfileCodec));
266  outputVideo->setupVideoEncoder(outputFrameDesc, profile);
267  _outputEncoder = outputVideo;
268 
269  // output stream
270  _outputStream = &outputFile.addVideoStream(outputVideo->getVideoCodec());
271  }
272  else if(profile.find(constants::avProfileType)->second == constants::avProfileTypeAudio)
273  {
274  const AudioCodec& inputAudioCodec = static_cast<const AudioCodec&>(inputCodec);
275  // generator decoder
276  _generator = new AudioGenerator(inputAudioCodec.getAudioFrameDesc());
278 
279  // filter
280  _filterGraph = new FilterGraph(inputAudioCodec);
281 
282  // buffers to process
283  AudioFrameDesc inputFrameDesc = inputAudioCodec.getAudioFrameDesc();
284  AudioFrameDesc outputFrameDesc = inputFrameDesc;
285  outputFrameDesc.setParameters(profile);
286  _sourceBuffer = new AudioFrame(inputFrameDesc);
287  _frameBuffer = new AudioFrame(outputFrameDesc);
288 
289  // transform
290  _transform = new AudioTransform();
291 
292  // output encoder
293  AudioEncoder* outputAudio = new AudioEncoder(profile.at(constants::avProfileCodec));
294  outputAudio->setupAudioEncoder(outputFrameDesc, profile);
295  _outputEncoder = outputAudio;
296 
297  // output stream
298  _outputStream = &outputFile.addAudioStream(outputAudio->getAudioCodec());
299  }
300  else
301  {
302  throw std::runtime_error("unupported stream type");
303  }
304 }
305 
307 {
308  delete _sourceBuffer;
309  delete _frameBuffer;
310  delete _generator;
311  delete _outputEncoder;
312  delete _transform;
313  delete _filterGraph;
314  delete _inputDecoder;
315 }
316 
318 {
319  if(!_outputEncoder)
320  {
321  std::stringstream msg;
322  msg << "No encoder found for input stream ";
324  msg << "generator";
325  else
326  msg << _inputStream->getStreamIndex();
327  msg << ": will not preProcessCodecLatency.";
328  LOG_WARN(msg.str())
329  return;
330  }
331 
332  int latency = _outputEncoder->getCodec().getLatency();
333 
334  LOG_DEBUG("Latency of stream: " << latency)
335 
336  if(!latency || latency < _outputEncoder->getCodec().getAVCodecContext().frame_number)
337  return;
338 
339  // set a decoder to preload generated frames
340  bool wasARewrapCase = false;
342  {
344  wasARewrapCase = true;
345  }
346 
347  while((latency--) > 0)
348  {
349  processFrame();
350  }
351 
352  if(wasARewrapCase)
353  _currentDecoder = NULL;
354 }
355 
357 {
358  const EProcessCase processCase = getProcessCase();
359  std::string msg = "Current process case of the stream is a ";
360  switch(processCase)
361  {
363  msg += "transcode.";
364  break;
365  case eProcessCaseRewrap:
366  msg += "rewrap.";
367  break;
369  msg += "generator.";
370  break;
371  }
372  LOG_DEBUG(msg)
373 
374  if(processCase == eProcessCaseGenerator)
375  return processTranscode();
376 
377  // Manage offset
378  if(_offset > 0)
379  {
380  const bool endOfOffset = _outputStream->getStreamDuration() >= _offset;
381  if(endOfOffset)
382  {
383  LOG_INFO("End of positive offset")
384 
387  else
388  _currentDecoder = NULL;
389  _offset = 0;
390  }
391  else
392  {
393  // process generator
395  {
397  }
398  }
399  }
400  else if(_offset < 0)
401  {
402  const bool endOfStream =
404  if(endOfStream)
405  {
406  LOG_INFO("End of negative offset")
407 
409  _offset = 0;
410  }
411  }
412 
413  if(processCase == eProcessCaseRewrap)
414  return processRewrap();
415 
417 }
418 
420 {
421  assert(_inputStream != NULL);
422  assert(_outputStream != NULL);
423  assert(_inputDecoder == NULL);
424 
425  LOG_DEBUG("StreamTranscoder::processRewrap")
426 
427  // if switched to generator, process frame
429  {
430  return processTranscode();
431  }
432 
433  CodedData data;
434  if(!_inputStream->readNextPacket(data))
435  {
437  {
439  return processTranscode();
440  }
441  return false;
442  }
443 
444  const IOutputStream::EWrappingStatus wrappingStatus = _outputStream->wrap(data);
445  switch(wrappingStatus)
446  {
448  return true;
450  // the wrapper needs more data to write the current packet
451  return processFrame();
453  return false;
454  }
455 
456  return true;
457 }
458 
459 bool StreamTranscoder::processTranscode(const int subStreamIndex)
460 {
461  assert(_outputStream != NULL);
462  assert(_currentDecoder != NULL);
463  assert(_outputEncoder != NULL);
464  assert(_sourceBuffer != NULL);
465  assert(_frameBuffer != NULL);
466  assert(_transform != NULL);
467 
468  LOG_DEBUG("StreamTranscoder::processTranscode")
469 
470  LOG_DEBUG("Decode next frame")
471  bool decodingStatus = false;
472  if(subStreamIndex < 0)
473  decodingStatus = _currentDecoder->decodeNextFrame(*_sourceBuffer);
474  else
475  decodingStatus = _currentDecoder->decodeNextFrame(*_sourceBuffer, subStreamIndex);
476 
477  CodedData data;
478  if(decodingStatus)
479  {
480  LOG_DEBUG("Filtering")
482 
483  LOG_DEBUG("Convert")
485 
486  LOG_DEBUG("Encode")
488  }
489  else
490  {
491  LOG_DEBUG("Encode last frame(s)")
492  if(!_outputEncoder->encodeFrame(data))
493  {
495  {
497  return processTranscode();
498  }
499  return false;
500  }
501  }
502 
503  LOG_DEBUG("wrap (" << data.getSize() << " bytes)")
504  const IOutputStream::EWrappingStatus wrappingStatus = _outputStream->wrap(data);
505  switch(wrappingStatus)
506  {
508  return true;
510  // the wrapper needs more data to write the current packet
511  return processFrame();
513  return false;
514  }
515 
516  return true;
517 }
518 
520 {
521  LOG_INFO("Switch to generator decoder")
522 
524  assert(_currentDecoder != NULL);
525 }
526 
528 {
529  LOG_INFO("Switch to input decoder")
530 
532  assert(_currentDecoder != NULL);
533 }
534 
536 {
537  if(_inputStream)
538  {
539  const StreamProperties& streamProperties = _inputStream->getProperties();
540  const float totalDuration = streamProperties.getDuration() + _offset;
541  if(totalDuration < 0)
542  {
543  LOG_WARN("Offset of " << _offset << "s applied to a stream with a duration of " << streamProperties.getDuration()
544  << "s. Set its duration to 0s.")
545  return 0.;
546  }
547  return totalDuration;
548  }
549  // generator
550  else
551  return std::numeric_limits<float>::max();
552 }
553 
555 {
557  return true;
558  return false;
559 }
560 
561 void StreamTranscoder::needToSwitchToGenerator(const bool needToSwitch)
562 {
563  if(needToSwitch && !canSwitchToGenerator())
564  {
565  std::stringstream os;
566  LOG_WARN("The stream " << _inputStream->getStreamIndex() << " has a duration of " << getDuration()
567  << "s. It needs to switch to a generator during the process, but it cannot. "
568  << "No generator will be used for this stream.")
569  return;
570  }
571  _needToSwitchToGenerator = needToSwitch;
572 }
573 
574 void StreamTranscoder::setOffset(const float offset)
575 {
576  _offset = offset;
577  if(_offset > 0)
579 }
580 
582 {
584  return eProcessCaseTranscode;
586  return eProcessCaseRewrap;
587  else
588  return eProcessCaseGenerator;
589 }
590 }
bool canSwitchToGenerator()
Returns if the stream has the ability to switch to a generator.
Description to create a video frame.
Definition: VideoFrame.hpp:21
AVMediaType getStreamType() const
AudioCodec & getAudioCodec()
This class describes decoded video data.
Definition: VideoFrame.hpp:43
virtual bool readNextPacket(CodedData &data)=0
Read the next packet of the stream.
EProcessCase getProcessCase() const
virtual const StreamProperties & getProperties() const =0
IOutputfile is the interface to wrap and write medias. It can be overloaded to integrate custom wrapp...
Definition: IOutputFile.hpp:22
IDecoder * _inputDecoder
Decoder of packets read from _inputStream (has ownership)
virtual EWrappingStatus wrap(const CodedData &data)=0
Wrap a packet of data.
void setupAudioEncoder(const AudioFrameDesc &frameDesc, const ProfileLoader::Profile &profile=ProfileLoader::Profile())
float getDuration() const
Get the total duration (in seconds), ie. duration of the stream and the offset applies.
Frame * _sourceBuffer
Has ownership.
void setupVideoEncoder(const VideoFrameDesc &frameDesc, const ProfileLoader::Profile &profile=ProfileLoader::Profile())
EWrappingStatus
define wrapping result status
virtual IOutputStream & addVideoStream(const VideoCodec &videoCodec)
Add a video output stream.
Definition: IOutputFile.hpp:31
void setOffset(const float offset)
IDecoder * _generator
Generator of audio or video packets (has ownership)
std::map< std::string, std::string > Profile
const std::string avProfileTypeAudio
const std::string avProfileTypeVideo
#define LOG_INFO(...)
Definition: log.hpp:23
float getDuration() const
in seconds
virtual bool encodeFrame(const Frame &sourceFrame, CodedData &codedFrame)=0
Encode a new frame, and get coded frame.
bool processTranscode(const int subStreamIndex=-1)
By default transcode all channels.
VideoCodec & getVideoCodec()
IEncoder * _outputEncoder
Encoder of packets which will be wrapped by _outputStream (has ownership)
int _subStreamIndex
Index of channel that is processed from the input stream (<0 if no demultiplexing).
AudioFrameDesc getAudioFrameDesc() const
Definition: AudioCodec.cpp:24
IDecoder * _currentDecoder
Link to _inputDecoder or _generator.
virtual float getStreamDuration() const =0
#define LOG_WARN(...)
Definition: log.hpp:29
Description to create an audio frame. This corresponds to the number of samples, which corresponds to...
Definition: AudioFrame.hpp:14
virtual IOutputStream & addDataStream(const DataCodec &dataCodec)
Add a data output stream.
Definition: IOutputFile.hpp:49
int getLatency() const
Definition: ICodec.cpp:100
bool processFrame()
process a single frame for the current stream
std::string getCodecName() const
Definition: ICodec.cpp:84
void preProcessCodecLatency()
Pre-process codec latency.
Frame * _frameBuffer
Has ownership.
virtual void convert(const Frame &src, Frame &dst)=0
virtual IOutputStream & addAudioStream(const AudioCodec &audioCodec)
Add an audio output stream.
Definition: IOutputFile.hpp:40
IOutputStream * _outputStream
Output stream to wrap next packet (has link, no ownership)
void setParameters(const ProfileLoader::Profile &profile)
Set the attributes from the given profile.
Definition: AudioFrame.cpp:29
FilterGraph * _filterGraph
Filter graph (has ownership)
void needToSwitchToGenerator(const bool needToSwitch=true)
Set if the stream needs to switch to a generator when ended.
size_t getSize() const
Definition: CodedData.hpp:70
This class describes decoded audio data.
Definition: AudioFrame.hpp:36
virtual ICodec & getCodec()=0
Get codec used for encoding.
virtual AudioCodec & getAudioCodec()=0
void process(Frame &frame)
Pull filtered data from the filter graph, and put result to the given frame.
Definition: FilterGraph.cpp:38
Virtual based class of properties for all types of stream.
Manager of filters.
Definition: FilterGraph.hpp:21
IInputStream * _inputStream
Input stream to read next packet (has link, no ownership)
#define LOG_DEBUG(...)
Definition: log.hpp:17
This class describes coded data.
Definition: CodedData.hpp:18
const std::string avProfileCodec
float _offset
Offset, in seconds, at the beginning of the StreamTranscoder.
void setParameters(const ProfileLoader::Profile &profile)
Set the attributes from the given profile.
Definition: VideoFrame.cpp:32
virtual bool decodeNextFrame(Frame &frameBuffer)=0
Decode next frame.
VideoFrameDesc getVideoFrameDesc() const
Definition: VideoCodec.cpp:24
virtual VideoCodec & getVideoCodec()=0
const std::string avProfileType
ITransform * _transform
Video or audio transform (has ownership)
virtual size_t getStreamIndex() const =0
virtual DataCodec & getDataCodec()=0
StreamTranscoder(const StreamTranscoder &streamTranscoder)
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