Skip to content

Commit ac206c9

Browse files
committed
Merge pull request #169 from cchampet/fix_timingOfPackets
OutputFile: copy timing information to wrapped packets
2 parents 6c4eaca + 8efb9b3 commit ac206c9

26 files changed

+284
-149
lines changed

src/AvTranscoder/file/InputFile.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ bool InputFile::readNextPacket( CodedData& data, const size_t streamIndex )
6767
return false;
6868
}
6969

70+
// Add Stream info to the packet
71+
data.refAVStream( _formatContext.getAVStream( streamIndex ) );
72+
7073
// if the packet stream is the expected one
7174
// return the packet data
7275
const int packetStreamIndex = data.getAVPacket().stream_index;

src/AvTranscoder/file/OutputFile.cpp

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,17 @@ IOutputStream& OutputFile::addDataStream( const DataCodec& dataDesc )
104104
IOutputStream& OutputFile::getStream( const size_t streamIndex )
105105
{
106106
if( streamIndex >= _outputStreams.size() )
107-
throw std::runtime_error( "unable to get output stream (out of range)" );
107+
{
108+
std::stringstream msg;
109+
msg << "Unable to get the stream ";
110+
msg << streamIndex;
111+
msg << ": the OutputFile '";
112+
msg << getFilename();
113+
msg << "' has only ";
114+
msg << _outputStreams.size();
115+
msg << " streams.";
116+
throw std::runtime_error( msg.str() );
117+
}
108118
return *_outputStreams.at( streamIndex );
109119
}
110120

@@ -166,16 +176,46 @@ IOutputStream::EWrappingStatus OutputFile::wrap( const CodedData& data, const si
166176

167177
LOG_DEBUG( "Wrap on stream " << streamIndex << " (" << data.getSize() << " bytes for frame " << _frameCount.at( streamIndex ) << ")" )
168178

179+
// Packet to wrap
169180
AVPacket packet;
170181
av_init_packet( &packet );
171182
packet.stream_index = streamIndex;
172183
packet.data = (uint8_t*)data.getData();
173184
packet.size = data.getSize();
185+
packet.flags = data.getAVPacket().flags;
174186

175-
_formatContext.writeFrame( packet );
187+
// copy timing information
188+
if( ! _outputStreams.at( streamIndex )->isPTSGenerated() )
189+
{
190+
if( data.getAVStream() != NULL )
191+
{
192+
const AVRational& srcTimeBase = data.getAVStream()->time_base;
193+
const AVRational& dstTimeBase = _formatContext.getAVStream( streamIndex ).time_base;
194+
// duration
195+
packet.duration = av_rescale_q( data.getAVPacket().duration, srcTimeBase, dstTimeBase );
196+
// pts
197+
if( data.getAVPacket().pts != AV_NOPTS_VALUE )
198+
packet.pts = av_rescale_q( data.getAVPacket().pts, srcTimeBase, dstTimeBase );
199+
else
200+
packet.pts = AV_NOPTS_VALUE;
201+
// dts
202+
packet.dts = av_rescale_q( data.getAVPacket().dts, srcTimeBase, dstTimeBase );
203+
}
204+
// add stream PTS if already incremented
205+
const int currentStreamPTS = _outputStreams.at( streamIndex )->getStreamPTS();
206+
if( packet.pts != AV_NOPTS_VALUE && packet.pts < currentStreamPTS )
207+
{
208+
packet.pts += currentStreamPTS;
209+
packet.dts += currentStreamPTS;
210+
}
211+
}
176212

177-
// free packet.side_data, set packet.data to NULL and packet.size to 0
178-
av_free_packet( &packet );
213+
// copy duration of packet wrapped
214+
// @see OutputStream
215+
const_cast<CodedData&>(data).getAVPacket().duration = packet.duration;
216+
217+
// Write packet
218+
_formatContext.writeFrame( packet );
179219

180220
const double currentStreamDuration = _outputStreams.at( streamIndex )->getStreamDuration();
181221
if( currentStreamDuration < _previousProcessedStreamDuration )

src/AvTranscoder/frame/Frame.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,33 @@ namespace avtranscoder
66
{
77

88
Frame::Frame()
9+
: _avStream( NULL )
910
{
1011
initAVPacket();
1112
}
1213

1314
Frame::Frame( const size_t dataSize )
15+
: _avStream( NULL )
1416
{
1517
av_new_packet( &_packet, dataSize );
1618
}
1719

1820
Frame::Frame( const AVPacket& avPacket )
21+
: _avStream( NULL )
1922
{
2023
copyAVPacket( avPacket );
2124
}
2225

2326
Frame::Frame( const Frame& other )
2427
{
2528
copyAVPacket( other.getAVPacket() );
29+
_avStream = other.getAVStream();
2630
}
2731

2832
Frame& Frame::operator=( const Frame& other )
2933
{
3034
copyAVPacket( other.getAVPacket() );
35+
_avStream = other.getAVStream();
3136
return *this;
3237
}
3338

src/AvTranscoder/frame/Frame.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ extern "C" {
77
#include <libavcodec/avcodec.h>
88
}
99

10+
struct AVStream;
11+
1012
namespace avtranscoder
1113
{
1214

@@ -33,6 +35,7 @@ class AvExport Frame
3335
/// Free buffer of data
3436
~Frame();
3537

38+
void refAVStream( const AVStream& avStream ) { _avStream = &avStream; }
3639
/// Resize data buffer
3740
void resize( const size_t newSize );
3841

@@ -58,6 +61,11 @@ class AvExport Frame
5861
size_t getSize() const { return _packet.size; }
5962

6063
#ifndef SWIG
64+
/**
65+
* @return the AVStream which contains the packet
66+
* @note may be NULL in case of generated packets
67+
*/
68+
const AVStream* getAVStream() const { return _avStream; }
6169
AVPacket& getAVPacket() { return _packet; }
6270
const AVPacket& getAVPacket() const { return _packet; }
6371
const unsigned char* getData() const { return _packet.data; }
@@ -69,6 +77,9 @@ class AvExport Frame
6977

7078
private:
7179
AVPacket _packet;
80+
81+
// Stream which contains the packet
82+
const AVStream* _avStream; //< Has link (no ownership)
7283
};
7384

7485
// Typedef to represent buffer of coded data.

src/AvTranscoder/mediaProperty/StreamProperties.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,13 @@ Rational StreamProperties::getTimeBase() const
2929
{
3030
if( ! _formatContext )
3131
throw std::runtime_error( "unknown format context" );
32-
33-
Rational timeBase = {
34-
_formatContext->streams[_streamIndex]->time_base.num,
35-
_formatContext->streams[_streamIndex]->time_base.den,
36-
};
37-
return timeBase;
32+
return _formatContext->streams[_streamIndex]->time_base;
3833
}
3934

4035
float StreamProperties::getDuration() const
4136
{
42-
Rational timeBase = getTimeBase();
43-
return ( timeBase.num / (float) timeBase.den ) * _formatContext->streams[_streamIndex]->duration;
37+
const Rational timeBase = getTimeBase();
38+
return av_q2d( timeBase ) * _formatContext->streams[_streamIndex]->duration;
4439
}
4540

4641
AVMediaType StreamProperties::getStreamType() const

src/AvTranscoder/stream/OutputStream.cpp

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ OutputStream::OutputStream( OutputFile& outputFile, const size_t streamIndex )
1313
, _outputAVStream( outputFile.getFormatContext().getAVStream( streamIndex ) )
1414
, _streamIndex( streamIndex )
1515
, _wrappedPacketsDuration( 0 )
16+
, _lastWrappedPacketDuration( 0 )
17+
, _isPTSGenerated( false )
1618
{
1719
}
1820

@@ -28,14 +30,8 @@ float OutputStream::getStreamDuration() const
2830
return 0.f;
2931
}
3032

31-
// if stream PTS is not set, use the duration of all packets wrapped
32-
if( ! outputPTS.val )
33-
{
34-
LOG_WARN( "PTS generation when outputting stream " << _streamIndex << " is not set." )
35-
if( _wrappedPacketsDuration )
36-
return av_q2d( _outputAVStream.codec->time_base ) * _wrappedPacketsDuration;
37-
}
38-
33+
if( _wrappedPacketsDuration )
34+
return av_q2d( outputTimeBase ) * _wrappedPacketsDuration;
3935
#if AVTRANSCODER_FFMPEG_DEPENDENCY && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(55, 40, 100)
4036
// returns the pts of the last muxed packet, converted from timebase to seconds
4137
return av_q2d( outputTimeBase ) * av_stream_get_end_pts( &_outputAVStream );
@@ -49,13 +45,61 @@ size_t OutputStream::getNbFrames() const
4945
return _outputAVStream.nb_frames;
5046
}
5147

48+
int OutputStream::getStreamPTS() const
49+
{
50+
const AVFrac& outputPTS = _outputAVStream.pts;
51+
return ( outputPTS.val + ( outputPTS.num / outputPTS.den ) );
52+
}
53+
5254
IOutputStream::EWrappingStatus OutputStream::wrap( const CodedData& data )
5355
{
56+
// If stream PTS will be generated at rewrap time
57+
if( ! _isPTSGenerated && (data.getAVPacket().pts == 0 || data.getAVPacket().pts == AV_NOPTS_VALUE) && data.getAVPacket().dts == AV_NOPTS_VALUE )
58+
{
59+
LOG_WARN( "PTS of output stream " << _streamIndex << " is generated at rewrap time." )
60+
_isPTSGenerated = true;
61+
}
62+
5463
// wrap packet
5564
IOutputStream::EWrappingStatus status = _outputFile.wrap( data, _streamIndex );
5665

57-
// append duration of the packet to the stream
58-
_wrappedPacketsDuration += data.getAVPacket().duration;
66+
// Store duration of the last packet wrapped
67+
if( data.getAVPacket().duration != 0 && data.getAVPacket().duration != _lastWrappedPacketDuration )
68+
_lastWrappedPacketDuration = data.getAVPacket().duration;
69+
70+
// Append duration of the packet to the stream
71+
if( data.getAVPacket().duration )
72+
_wrappedPacketsDuration += data.getAVPacket().duration;
73+
else
74+
{
75+
switch( _outputAVStream.codec->codec_type )
76+
{
77+
case AVMEDIA_TYPE_VIDEO:
78+
{
79+
_wrappedPacketsDuration += _lastWrappedPacketDuration;
80+
break;
81+
}
82+
case AVMEDIA_TYPE_AUDIO:
83+
{
84+
Rational audioPacketDuration;
85+
audioPacketDuration.num = 0;
86+
audioPacketDuration.den = 0;
87+
const int frame_size = av_get_audio_frame_duration(_outputAVStream.codec, data.getSize());
88+
if( frame_size <= 0 || _outputAVStream.codec->sample_rate <= 0 )
89+
break;
90+
audioPacketDuration.num = frame_size;
91+
audioPacketDuration.den = _outputAVStream.codec->sample_rate;
92+
_wrappedPacketsDuration += av_rescale(
93+
1,
94+
audioPacketDuration.num * (int64_t)_outputAVStream.time_base.den * _outputAVStream.codec->ticks_per_frame,
95+
audioPacketDuration.den * (int64_t)_outputAVStream.time_base.num
96+
);
97+
break;
98+
}
99+
default:
100+
break;
101+
}
102+
}
59103

60104
return status;
61105
}

src/AvTranscoder/stream/OutputStream.hpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ class AvExport OutputStream : public IOutputStream
1818
size_t getStreamIndex() const { return _streamIndex; }
1919
float getStreamDuration() const;
2020
size_t getNbFrames() const; ///< If audio stream, returns number of packets
21+
int getStreamPTS() const; ///< Get current AVStream PTS
2122

23+
bool isPTSGenerated() const { return _isPTSGenerated; }
2224
IOutputStream::EWrappingStatus wrap( const CodedData& data );
2325

2426
private:
@@ -27,12 +29,14 @@ class AvExport OutputStream : public IOutputStream
2729

2830
size_t _streamIndex; ///< Index of the stream in the output file
2931

30-
/**
31-
* @brief This will help us to getStreamDuration if PTS of outputStream is not properly set during wrapping.
32-
* It corresponds to the addition of the duration of all packets wrapped by this stream.
33-
* @see getStreamDuration
34-
*/
35-
size_t _wrappedPacketsDuration;
32+
//@{
33+
// @brief These attributes will help us to get the stream duration.
34+
// @see ffmpeg hack: https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/mux.c#L585
35+
// @see getStreamDuration
36+
size_t _wrappedPacketsDuration; //< the addition of the duration of all packets wrapped by this stream.
37+
int _lastWrappedPacketDuration; //< The duration of the last packet wrapped by this stream.
38+
bool _isPTSGenerated; //< Is the PTS generated by ffmpeg/libav (in case of generator for example)
39+
//@}
3640
};
3741

3842
}

src/AvTranscoder/transcoder/StreamTranscoder.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -319,15 +319,14 @@ void StreamTranscoder::preProcessCodecLatency()
319319
{
320320
if( ! _outputEncoder )
321321
{
322-
std::stringstream os;
323-
os << "No output encoder found for stream ";
322+
std::stringstream msg;
323+
msg << "No encoder found for input stream ";
324324
if( getProcessCase() == eProcessCaseGenerator )
325-
os << "generator";
325+
msg << "generator";
326326
else
327-
os << _inputStream->getStreamIndex();
328-
os << ": will not preProcessCodecLatency.";
329-
LOG_INFO( os.str() )
330-
327+
msg << _inputStream->getStreamIndex();
328+
msg << ": will not preProcessCodecLatency.";
329+
LOG_WARN( msg.str() )
331330
return;
332331
}
333332

@@ -408,7 +407,7 @@ bool StreamTranscoder::processRewrap()
408407
LOG_DEBUG( "StreamTranscoder::processRewrap" )
409408

410409
// if switched to generator, process frame
411-
if( _currentDecoder == _generator )
410+
if( _currentDecoder && _currentDecoder == _generator )
412411
{
413412
return processTranscode();
414413
}

src/AvTranscoder/transcoder/StreamTranscoder.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ class AvExport StreamTranscoder
7070
*/
7171
float getDuration() const;
7272

73-
/// Returns a reference to the current decoder (from input file or from generator)
74-
IDecoder& getCurrentDecoder() const { return *_currentDecoder; }
75-
/// Returns a reference to the encoder
76-
IEncoder& getEncoder() const { return *_outputEncoder; }
73+
/// Returns a pointer to the current decoder (from input file or from generator)
74+
IDecoder* getCurrentDecoder() const { return _currentDecoder; }
75+
/// Returns a pointer to the encoder
76+
IEncoder* getEncoder() const { return _outputEncoder; }
7777

7878
/// Returns a reference to the object which transforms the decoded data
7979
ITransform& getTransform() const { return *_transform; }

src/AvTranscoder/transcoder/Transcoder.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,14 +241,14 @@ ProcessStat Transcoder::process( IProgress& progress )
241241

242242
preProcessCodecLatency();
243243

244-
const double outputDuration = getOutputDuration();
244+
const float outputDuration = getOutputDuration();
245245
LOG_INFO( "Output duration of the process will be " << outputDuration << "s." )
246246

247247
size_t frame = 0;
248248
bool frameProcessed = true;
249249
while( frameProcessed )
250250
{
251-
const double progressDuration = _outputFile.getStream( 0 ).getStreamDuration();
251+
const float progressDuration = _outputFile.getStream( 0 ).getStreamDuration();
252252

253253
// check if JobStatusCancel
254254
if( progress.progress( ( progressDuration > outputDuration ) ? outputDuration : progressDuration, outputDuration ) == eJobStatusCancel )
@@ -528,11 +528,15 @@ void Transcoder::fillProcessStat( ProcessStat& processStat )
528528
case AVMEDIA_TYPE_VIDEO:
529529
{
530530
VideoStat videoStat( stream.getStreamDuration(), stream.getNbFrames() );
531-
const AVCodecContext& encoderContext = _streamTranscoders.at( streamIndex )->getEncoder().getCodec().getAVCodecContext();
532-
if( encoderContext.coded_frame && ( encoderContext.flags & CODEC_FLAG_PSNR) )
531+
IEncoder* encoder = _streamTranscoders.at( streamIndex )->getEncoder();
532+
if( encoder )
533533
{
534-
videoStat._quality = encoderContext.coded_frame->quality;
535-
videoStat._psnr = VideoStat::psnr( encoderContext.coded_frame->error[0] / ( encoderContext.width * encoderContext.height * 255.0 * 255.0 ) );
534+
const AVCodecContext& encoderContext = encoder->getCodec().getAVCodecContext();
535+
if( encoderContext.coded_frame && ( encoderContext.flags & CODEC_FLAG_PSNR) )
536+
{
537+
videoStat._quality = encoderContext.coded_frame->quality;
538+
videoStat._psnr = VideoStat::psnr( encoderContext.coded_frame->error[0] / ( encoderContext.width * encoderContext.height * 255.0 * 255.0 ) );
539+
}
536540
}
537541
processStat.addVideoStat( streamIndex, videoStat );
538542
break;

0 commit comments

Comments
 (0)
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