Skip to content

Commit 5fa0d73

Browse files
committed
Merge pull request #243 from cchampet/fix_encoderInstanciationIfRewrap
StreamTranscoder: catch error if cannot create encoder in cases of rewrapping
2 parents 21fac64 + c75186f commit 5fa0d73

File tree

5 files changed

+139
-68
lines changed

5 files changed

+139
-68
lines changed

src/AvTranscoder/file/OutputFile.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ IOutputStream& OutputFile::addVideoStream( const VideoCodec& videoDesc )
4949

5050
stream.time_base = stream.codec->time_base;
5151

52-
OutputStream* avOutputStream = new OutputStream( *this, _formatContext.getNbStreams() - 1 );
53-
_outputStreams.push_back( avOutputStream );
52+
OutputStream* outputStream = new OutputStream( *this, _formatContext.getNbStreams() - 1 );
53+
_outputStreams.push_back( outputStream );
5454

55-
return *_outputStreams.back();
55+
return *outputStream;
5656
}
5757

5858
IOutputStream& OutputFile::addAudioStream( const AudioCodec& audioDesc )
@@ -63,20 +63,21 @@ IOutputStream& OutputFile::addAudioStream( const AudioCodec& audioDesc )
6363
stream.codec->channels = audioDesc.getAVCodecContext().channels;
6464
stream.codec->sample_fmt = audioDesc.getAVCodecContext().sample_fmt;
6565

66-
OutputStream* avOutputStream = new OutputStream( *this, _formatContext.getNbStreams() - 1 );
67-
_outputStreams.push_back( avOutputStream );
6866

69-
return *_outputStreams.back();
67+
OutputStream* outputStream = new OutputStream( *this, _formatContext.getNbStreams() - 1 );
68+
_outputStreams.push_back( outputStream );
69+
70+
return *outputStream;
7071
}
7172

7273
IOutputStream& OutputFile::addDataStream( const DataCodec& dataDesc )
7374
{
7475
_formatContext.addAVStream( dataDesc.getAVCodec() );
7576

76-
OutputStream* avOutputStream = new OutputStream( *this, _formatContext.getNbStreams() - 1 );
77-
_outputStreams.push_back( avOutputStream );
77+
OutputStream* outputStream = new OutputStream( *this, _formatContext.getNbStreams() - 1 );
78+
_outputStreams.push_back( outputStream );
7879

79-
return *_outputStreams.back();
80+
return *outputStream;
8081
}
8182

8283
IOutputStream& OutputFile::getStream( const size_t streamId )

src/AvTranscoder/frame/Frame.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,11 @@ void Frame::initAVPacket()
8484

8585
void Frame::copyAVPacket( const AVPacket& avPacket )
8686
{
87-
#if AVTRANSCODER_FFMPEG_DEPENDENCY && LIBAVCODEC_VERSION_INT > AV_VERSION_INT(55, 56, 108)
88-
av_copy_packet( &_packet, &avPacket );
89-
#elif AVTRANSCODER_FFMPEG_DEPENDENCY && LIBAVCODEC_VERSION_INT > AV_VERSION_INT(54, 56, 0)
87+
#if AVTRANSCODER_FFMPEG_DEPENDENCY && LIBAVCODEC_VERSION_INT > AV_VERSION_INT(54, 56, 0)
88+
// Need const_cast<AVCodec*> for libav versions from 54.56. to 55.56.
9089
av_copy_packet( &_packet, const_cast<AVPacket*>( &avPacket ) );
9190
#else
92-
// we just care about data, not side properties of AVPacket
91+
// @todo: we just care about data, not side properties of AVPacket
9392
initAVPacket();
9493
copyData( avPacket.data, avPacket.size );
9594
#endif

src/AvTranscoder/transcoder/StreamTranscoder.cpp

Lines changed: 99 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -36,60 +36,75 @@ StreamTranscoder::StreamTranscoder(
3636
, _transform( NULL )
3737
, _subStreamIndex( -1 )
3838
, _offset( offset )
39-
, _canSwitchToGenerator( false )
39+
, _needToSwitchToGenerator( false )
4040
{
4141
// create a re-wrapping case
4242
switch( _inputStream->getStreamType() )
4343
{
4444
case AVMEDIA_TYPE_VIDEO :
4545
{
46-
VideoFrameDesc inputFrameDesc( _inputStream->getVideoCodec().getVideoFrameDesc() );
46+
// output stream
47+
_outputStream = &outputFile.addVideoStream( _inputStream->getVideoCodec() );
4748

48-
// generator decoder
49-
VideoGenerator* generatorVideo = new VideoGenerator();
50-
generatorVideo->setVideoFrameDesc( inputFrameDesc );
51-
_generator = generatorVideo;
49+
try
50+
{
51+
VideoFrameDesc inputFrameDesc( _inputStream->getVideoCodec().getVideoFrameDesc() );
5252

53-
// buffers to process
54-
_sourceBuffer = new VideoFrame( inputFrameDesc );
55-
_frameBuffer = new VideoFrame( inputFrameDesc );
53+
// generator decoder
54+
VideoGenerator* generatorVideo = new VideoGenerator();
55+
generatorVideo->setVideoFrameDesc( inputFrameDesc );
56+
_generator = generatorVideo;
5657

57-
// transform
58-
_transform = new VideoTransform();
58+
// buffers to process
59+
_sourceBuffer = new VideoFrame( inputFrameDesc );
60+
_frameBuffer = new VideoFrame( inputFrameDesc );
5961

60-
// output encoder
61-
VideoEncoder* outputVideo = new VideoEncoder( _inputStream->getVideoCodec().getCodecName() );
62-
outputVideo->setupVideoEncoder( inputFrameDesc );
63-
_outputEncoder = outputVideo;
62+
// transform
63+
_transform = new VideoTransform();
6464

65-
// output stream
66-
_outputStream = &outputFile.addVideoStream( _inputStream->getVideoCodec() );
65+
// output encoder
66+
VideoEncoder* outputVideo = new VideoEncoder( _inputStream->getVideoCodec().getCodecName() );
67+
outputVideo->setupVideoEncoder( inputFrameDesc );
68+
_outputEncoder = outputVideo;
69+
}
70+
catch( std::runtime_error& e )
71+
{
72+
LOG_WARN( "Cannot create the video encoder for stream " << _inputStream->getStreamIndex() << " if needed. " << e.what() )
73+
}
6774

6875
break;
6976
}
7077
case AVMEDIA_TYPE_AUDIO :
7178
{
72-
AudioFrameDesc inputFrameDesc( _inputStream->getAudioCodec().getAudioFrameDesc() );
79+
// output stream
80+
_outputStream = &outputFile.addAudioStream( _inputStream->getAudioCodec() );
7381

74-
// generator decoder
75-
AudioGenerator* generatorAudio = new AudioGenerator();
76-
generatorAudio->setAudioFrameDesc( inputFrameDesc );
77-
_generator = generatorAudio;
82+
try
83+
{
84+
AudioFrameDesc inputFrameDesc( _inputStream->getAudioCodec().getAudioFrameDesc() );
7885

79-
// buffers to process
80-
_sourceBuffer = new AudioFrame( inputFrameDesc );
81-
_frameBuffer = new AudioFrame( inputFrameDesc );
86+
// generator decoder
87+
AudioGenerator* generatorAudio = new AudioGenerator();
88+
generatorAudio->setAudioFrameDesc( inputFrameDesc );
89+
_generator = generatorAudio;
8290

83-
// transform
84-
_transform = new AudioTransform();
91+
// buffers to process
92+
_sourceBuffer = new AudioFrame( inputFrameDesc );
93+
_frameBuffer = new AudioFrame( inputFrameDesc );
8594

86-
// output encoder
87-
AudioEncoder* outputAudio = new AudioEncoder( _inputStream->getAudioCodec().getCodecName() );
88-
outputAudio->setupAudioEncoder( inputFrameDesc );
89-
_outputEncoder = outputAudio;
95+
// transform
96+
_transform = new AudioTransform();
9097

91-
// output stream
92-
_outputStream = &outputFile.addAudioStream( _inputStream->getAudioCodec() );
98+
// output encoder
99+
AudioEncoder* outputAudio = new AudioEncoder( _inputStream->getAudioCodec().getCodecName() );
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. " << e.what() )
107+
}
93108

94109
break;
95110
}
@@ -102,6 +117,7 @@ StreamTranscoder::StreamTranscoder(
102117
default:
103118
break;
104119
}
120+
setOffset( offset );
105121
}
106122

107123
StreamTranscoder::StreamTranscoder(
@@ -122,7 +138,7 @@ StreamTranscoder::StreamTranscoder(
122138
, _transform( NULL )
123139
, _subStreamIndex( subStreamIndex )
124140
, _offset( offset )
125-
, _canSwitchToGenerator( false )
141+
, _needToSwitchToGenerator( false )
126142
{
127143
// create a transcode case
128144
switch( _inputStream->getStreamType() )
@@ -208,6 +224,7 @@ StreamTranscoder::StreamTranscoder(
208224
break;
209225
}
210226
}
227+
setOffset( offset );
211228
}
212229

213230
StreamTranscoder::StreamTranscoder(
@@ -226,7 +243,7 @@ StreamTranscoder::StreamTranscoder(
226243
, _transform( NULL )
227244
, _subStreamIndex( -1 )
228245
, _offset( 0 )
229-
, _canSwitchToGenerator( false )
246+
, _needToSwitchToGenerator( false )
230247
{
231248
if( profile.find( constants::avProfileType )->second == constants::avProfileTypeVideo )
232249
{
@@ -300,6 +317,20 @@ StreamTranscoder::~StreamTranscoder()
300317

301318
void StreamTranscoder::preProcessCodecLatency()
302319
{
320+
if( ! _outputEncoder )
321+
{
322+
std::stringstream os;
323+
os << "No output encoder found for stream ";
324+
if( getProcessCase() == eProcessCaseGenerator )
325+
os << "generator";
326+
else
327+
os << _inputStream->getStreamIndex();
328+
os << ": will not preProcessCodecLatency.";
329+
LOG_INFO( os.str() )
330+
331+
return;
332+
}
333+
303334
int latency = _outputEncoder->getCodec().getLatency();
304335

305336
LOG_DEBUG( "Latency of stream: " << latency )
@@ -323,6 +354,9 @@ void StreamTranscoder::preProcessCodecLatency()
323354

324355
bool StreamTranscoder::processFrame()
325356
{
357+
if( getProcessCase() == eProcessCaseGenerator )
358+
return processTranscode();
359+
326360
// Manage offset
327361
if( _offset > 0 )
328362
{
@@ -357,7 +391,7 @@ bool StreamTranscoder::processFrame()
357391
switchToGeneratorDecoder();
358392
_offset = 0;
359393
}
360-
}
394+
}
361395

362396
if( getProcessCase() == eProcessCaseRewrap )
363397
return processRewrap();
@@ -382,7 +416,7 @@ bool StreamTranscoder::processRewrap()
382416
CodedData data;
383417
if( ! _inputStream->readNextPacket( data ) )
384418
{
385-
if( _canSwitchToGenerator )
419+
if( _needToSwitchToGenerator )
386420
{
387421
switchToGeneratorDecoder();
388422
return processTranscode();
@@ -437,7 +471,7 @@ bool StreamTranscoder::processTranscode( const int subStreamIndex )
437471
LOG_DEBUG( "Encode last frame(s)" )
438472
if( ! _outputEncoder->encodeFrame( data ) )
439473
{
440-
if( _canSwitchToGenerator )
474+
if( _needToSwitchToGenerator )
441475
{
442476
switchToGeneratorDecoder();
443477
return processTranscode();
@@ -479,7 +513,7 @@ void StreamTranscoder::switchToInputDecoder()
479513
}
480514

481515
float StreamTranscoder::getDuration() const
482-
{
516+
{
483517
if( _inputStream )
484518
{
485519
const float totalDuration = _inputStream->getDuration() + _offset;
@@ -490,10 +524,36 @@ float StreamTranscoder::getDuration() const
490524
}
491525
return totalDuration;
492526
}
527+
// generator
493528
else
494529
return std::numeric_limits<float>::max();
495530
}
496531

532+
bool StreamTranscoder::canSwitchToGenerator()
533+
{
534+
if( _sourceBuffer && _frameBuffer && _generator && _outputEncoder && _transform )
535+
return true;
536+
return false;
537+
}
538+
539+
void StreamTranscoder::needToSwitchToGenerator( const bool needToSwitch )
540+
{
541+
if( needToSwitch && ! canSwitchToGenerator() )
542+
{
543+
std::stringstream os;
544+
os << "The stream " << _inputStream->getStreamIndex() << " needs to switch to a generator during the process, but it cannot.";
545+
throw std::runtime_error( os.str() );
546+
}
547+
_needToSwitchToGenerator = needToSwitch;
548+
}
549+
550+
void StreamTranscoder::setOffset( const float offset )
551+
{
552+
_offset = offset;
553+
if( _offset > 0 )
554+
needToSwitchToGenerator();
555+
}
556+
497557
StreamTranscoder::EProcessCase StreamTranscoder::getProcessCase() const
498558
{
499559
if( _inputStream && _inputDecoder )

src/AvTranscoder/transcoder/StreamTranscoder.hpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,22 @@ class AvExport StreamTranscoder
8484
IOutputStream& getOutputStream() const { return *_outputStream; }
8585

8686
/**
87-
* @brief Returns if the stream can switch to a generator when ended
88-
* @note Not applicable for rewrap and generator cases
87+
* @brief Returns if the stream has the ability to switch to a generator.
8988
*/
90-
void canSwitchToGenerator( bool canSwitch ) { _canSwitchToGenerator = canSwitch; }
89+
bool canSwitchToGenerator();
9190

92-
void setOffset( const float offset ){ _offset = offset; }
91+
/**
92+
* @brief Set if the stream needs to switch to a generator when ended
93+
* @note Throws a runtime_error exception if the stream cannot switch to a generator
94+
* @see canSwitchToGenerator
95+
*/
96+
void needToSwitchToGenerator( const bool needToSwitch = true );
97+
98+
/**
99+
* @note Throws a runtime_error exception if it's a positive offset and the stream cannot switch to a generator
100+
* @see needToSwitchToGenerator
101+
*/
102+
void setOffset( const float offset );
93103

94104
private:
95105
bool processRewrap();
@@ -123,7 +133,7 @@ class AvExport StreamTranscoder
123133

124134
float _offset; ///< Offset, in seconds, at the beginning of the StreamTranscoder.
125135

126-
bool _canSwitchToGenerator; ///< Automatically switch to a generator at the end of the stream
136+
bool _needToSwitchToGenerator; ///< Set if need to switch to a generator during the process (because, of other streams duration, or an offset)
127137
};
128138

129139
}

src/AvTranscoder/transcoder/Transcoder.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -483,34 +483,35 @@ void Transcoder::manageSwitchToGenerator()
483483
{
484484
for( size_t i = 0; i < _streamTranscoders.size(); ++i )
485485
{
486+
const float currentDuration = _streamTranscoders.at( i )->getDuration();
486487
switch( _eProcessMethod )
487488
{
488489
case eProcessMethodShortest :
489-
if( _streamTranscoders.at( i )->getDuration() == getMinTotalDuration() )
490-
_streamTranscoders.at( i )->canSwitchToGenerator( false );
490+
if( _streamTranscoders.at( i )->getDuration() >= getMinTotalDuration() )
491+
_streamTranscoders.at( i )->needToSwitchToGenerator( false );
491492
else
492-
_streamTranscoders.at( i )->canSwitchToGenerator( true );
493+
_streamTranscoders.at( i )->needToSwitchToGenerator();
493494
break;
494495
case eProcessMethodLongest :
495496
if( _streamTranscoders.at( i )->getDuration() == getMaxTotalDuration() )
496-
_streamTranscoders.at( i )->canSwitchToGenerator( false );
497+
_streamTranscoders.at( i )->needToSwitchToGenerator( false );
497498
else
498-
_streamTranscoders.at( i )->canSwitchToGenerator( true );
499+
_streamTranscoders.at( i )->needToSwitchToGenerator();
499500
break;
500501
case eProcessMethodBasedOnStream :
501-
if( i != _mainStreamIndex )
502-
_streamTranscoders.at( i )->canSwitchToGenerator( true );
502+
if( i != _mainStreamIndex && currentDuration < _streamTranscoders.at( _mainStreamIndex )->getDuration() )
503+
_streamTranscoders.at( i )->needToSwitchToGenerator();
503504
else
504-
_streamTranscoders.at( i )->canSwitchToGenerator( false );
505+
_streamTranscoders.at( i )->needToSwitchToGenerator( false );
505506
break;
506507
case eProcessMethodBasedOnDuration :
507508
if( _streamTranscoders.at( i )->getDuration() >= _outputDuration )
508-
_streamTranscoders.at( i )->canSwitchToGenerator( false );
509+
_streamTranscoders.at( i )->needToSwitchToGenerator( false );
509510
else
510-
_streamTranscoders.at( i )->canSwitchToGenerator( true );
511+
_streamTranscoders.at( i )->needToSwitchToGenerator();
511512
break;
512513
case eProcessMethodInfinity :
513-
_streamTranscoders.at( i )->canSwitchToGenerator( true );
514+
_streamTranscoders.at( i )->needToSwitchToGenerator();
514515
break;
515516
}
516517
}

0 commit comments

Comments
 (0)