Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3a973e2
Frame: added attribute to retreive info of stream which contains the …
Nov 17, 2015
b67d14e
InputFile: add ref to the stream for each packet read
Nov 17, 2015
9af22ef
OutputFile: copy timing information for each packet wrapped
Nov 17, 2015
379e501
OutputFile: do not manually free the packet after call of writeFrame
Nov 17, 2015
2277c6c
OutputFile: indicate packet flags when wrap it
Nov 17, 2015
acab155
OutputFile: check if the packet has a ref to its AVStream when wrap it
Nov 17, 2015
3d843af
Merge branch 'develop' of https://github.com/avTranscoder/avTranscode…
Nov 17, 2015
7fe7bd2
OutputFile: improved exception message when getStream
Nov 17, 2015
ccfd582
OutputStream: removed check if stream PTS is not set when getStreamDu…
Nov 17, 2015
15a5d3c
appveyor: update environment to launch all nosetests
Nov 18, 2015
971c5a7
StreamProperties: do not create a new Rational when getTimeBase
Nov 18, 2015
4d682cb
StreamProperties: use av_q2d function when getDuration
Nov 18, 2015
b4744a3
OutputStream: fix how to getStreamDuration
Nov 18, 2015
83d84e5
Transcoder: get duration as float in process method
Nov 18, 2015
d473606
pyTest: fix output file name of testEProcessMethodBasedOnStream
Nov 18, 2015
9e0b5ae
pyTest: simplify calls to add streams in testEProcessMethod
Nov 18, 2015
547d5d5
pyTest: do not check file bitrate in testTranscoderRewrap
Nov 18, 2015
2bcf34a
pyTest: add common function checkFormat in testTranscoderRewrap
Nov 18, 2015
f6c840e
pyTest: add common function checkStream in testTranscoderRewrap
Nov 18, 2015
83a6494
pyTest: skip stream metadata/streamId/streamIndex when check stream …
Nov 18, 2015
4d8f702
pyTest: add test to rewrap a video stream from a MOV file
Nov 18, 2015
0d6ca9f
pyTest: skip stream timeBase when check stream in testTranscoderRewrap
Nov 18, 2015
6ecca0a
pyTest: skip rewrap tests if all env is not defined
Nov 18, 2015
6eab86d
OutputFile: if the stream PTS is generated, do not copy timing inform…
Nov 18, 2015
8cd768b
pyTest: removed duplicate instructions in testOffset
Nov 18, 2015
fa1c43e
pyTest: add __init__.py to preload and set log level only once
Nov 18, 2015
332febf
CI: add AVTRANSCODER_TEST_VIDEO_MOV_FILE env variable for pyTests
Nov 19, 2015
2cb928f
OutputStream: add getStreamPTS method
Nov 19, 2015
2c552bc
OutputFile: add stream PTS to wrapped packet if already incremented
Nov 19, 2015
f5c8930
pyTest: fix testEProcessMethodBasedOnStream
Nov 19, 2015
fa3bab9
OutputStream: fix addition of last audio packet duration
Nov 19, 2015
19c6a1e
pyTest: check the exact output duration in offset tests
Nov 19, 2015
00809e5
pyTest: skip testMultipleOffsetFromSameInputFile
Nov 19, 2015
cf647dc
Transcoder: accessors to current decoder and encoder return a pointer
Nov 20, 2015
d8a3d34
Transcoder: check if the stream has an encoder when fillProcessStat
Nov 20, 2015
90e9401
StreamTranscoder: fix process of a generator in rewrap cases
Nov 20, 2015
61c0ca9
StreamTranscoder: log msg as warning when cannot preprocess codec lat…
Nov 20, 2015
aba5ff4
StreamTranscoder: fix log message which does not appear
Nov 20, 2015
059c05d
pyTest: improved indentation when skip tests
Nov 24, 2015
000c24a
pyTest: complete and disable testEProcessMethodBasedOnStream
Nov 24, 2015
5f09da6
OutputStream: improved indentation in wrap method
Nov 24, 2015
8efb9b3
pyTest: activate testEProcessMethodBasedOnStream
Nov 24, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/AvTranscoder/file/InputFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ bool InputFile::readNextPacket( CodedData& data, const size_t streamIndex )
return false;
}

// Add Stream info to the packet
data.refAVStream( _formatContext.getAVStream( streamIndex ) );

// if the packet stream is the expected one
// return the packet data
const int packetStreamIndex = data.getAVPacket().stream_index;
Expand Down
48 changes: 44 additions & 4 deletions src/AvTranscoder/file/OutputFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,17 @@ IOutputStream& OutputFile::addDataStream( const DataCodec& dataDesc )
IOutputStream& OutputFile::getStream( const size_t streamIndex )
{
if( streamIndex >= _outputStreams.size() )
throw std::runtime_error( "unable to get output stream (out of range)" );
{
std::stringstream msg;
msg << "Unable to get the stream ";
msg << streamIndex;
msg << ": the OutputFile '";
msg << getFilename();
msg << "' has only ";
msg << _outputStreams.size();
msg << " streams.";
throw std::runtime_error( msg.str() );
}
return *_outputStreams.at( streamIndex );
}

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

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

// Packet to wrap
AVPacket packet;
av_init_packet( &packet );
packet.stream_index = streamIndex;
packet.data = (uint8_t*)data.getData();
packet.size = data.getSize();
packet.flags = data.getAVPacket().flags;

_formatContext.writeFrame( packet );
// copy timing information
if( ! _outputStreams.at( streamIndex )->isPTSGenerated() )
{
if( data.getAVStream() != NULL )
{
const AVRational& srcTimeBase = data.getAVStream()->time_base;
const AVRational& dstTimeBase = _formatContext.getAVStream( streamIndex ).time_base;
// duration
packet.duration = av_rescale_q( data.getAVPacket().duration, srcTimeBase, dstTimeBase );
// pts
if( data.getAVPacket().pts != AV_NOPTS_VALUE )
packet.pts = av_rescale_q( data.getAVPacket().pts, srcTimeBase, dstTimeBase );
else
packet.pts = AV_NOPTS_VALUE;
// dts
packet.dts = av_rescale_q( data.getAVPacket().dts, srcTimeBase, dstTimeBase );
}
// add stream PTS if already incremented
const int currentStreamPTS = _outputStreams.at( streamIndex )->getStreamPTS();
if( packet.pts != AV_NOPTS_VALUE && packet.pts < currentStreamPTS )
{
packet.pts += currentStreamPTS;
packet.dts += currentStreamPTS;
}
}

// free packet.side_data, set packet.data to NULL and packet.size to 0
av_free_packet( &packet );
// copy duration of packet wrapped
// @see OutputStream
const_cast<CodedData&>(data).getAVPacket().duration = packet.duration;

// Write packet
_formatContext.writeFrame( packet );

const double currentStreamDuration = _outputStreams.at( streamIndex )->getStreamDuration();
if( currentStreamDuration < _previousProcessedStreamDuration )
Expand Down
5 changes: 5 additions & 0 deletions src/AvTranscoder/frame/Frame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,33 @@ namespace avtranscoder
{

Frame::Frame()
: _avStream( NULL )
{
initAVPacket();
}

Frame::Frame( const size_t dataSize )
: _avStream( NULL )
{
av_new_packet( &_packet, dataSize );
}

Frame::Frame( const AVPacket& avPacket )
: _avStream( NULL )
{
copyAVPacket( avPacket );
}

Frame::Frame( const Frame& other )
{
copyAVPacket( other.getAVPacket() );
_avStream = other.getAVStream();
}

Frame& Frame::operator=( const Frame& other )
{
copyAVPacket( other.getAVPacket() );
_avStream = other.getAVStream();
return *this;
}

Expand Down
11 changes: 11 additions & 0 deletions src/AvTranscoder/frame/Frame.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ extern "C" {
#include <libavcodec/avcodec.h>
}

struct AVStream;

namespace avtranscoder
{

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

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

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

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

private:
AVPacket _packet;

// Stream which contains the packet
const AVStream* _avStream; //< Has link (no ownership)
};

// Typedef to represent buffer of coded data.
Expand Down
11 changes: 3 additions & 8 deletions src/AvTranscoder/mediaProperty/StreamProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,13 @@ Rational StreamProperties::getTimeBase() const
{
if( ! _formatContext )
throw std::runtime_error( "unknown format context" );

Rational timeBase = {
_formatContext->streams[_streamIndex]->time_base.num,
_formatContext->streams[_streamIndex]->time_base.den,
};
return timeBase;
return _formatContext->streams[_streamIndex]->time_base;
}

float StreamProperties::getDuration() const
{
Rational timeBase = getTimeBase();
return ( timeBase.num / (float) timeBase.den ) * _formatContext->streams[_streamIndex]->duration;
const Rational timeBase = getTimeBase();
return av_q2d( timeBase ) * _formatContext->streams[_streamIndex]->duration;
}

AVMediaType StreamProperties::getStreamType() const
Expand Down
64 changes: 54 additions & 10 deletions src/AvTranscoder/stream/OutputStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ OutputStream::OutputStream( OutputFile& outputFile, const size_t streamIndex )
, _outputAVStream( outputFile.getFormatContext().getAVStream( streamIndex ) )
, _streamIndex( streamIndex )
, _wrappedPacketsDuration( 0 )
, _lastWrappedPacketDuration( 0 )
, _isPTSGenerated( false )
{
}

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

// if stream PTS is not set, use the duration of all packets wrapped
if( ! outputPTS.val )
{
LOG_WARN( "PTS generation when outputting stream " << _streamIndex << " is not set." )
if( _wrappedPacketsDuration )
return av_q2d( _outputAVStream.codec->time_base ) * _wrappedPacketsDuration;
}

if( _wrappedPacketsDuration )
return av_q2d( outputTimeBase ) * _wrappedPacketsDuration;
#if AVTRANSCODER_FFMPEG_DEPENDENCY && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(55, 40, 100)
// returns the pts of the last muxed packet, converted from timebase to seconds
return av_q2d( outputTimeBase ) * av_stream_get_end_pts( &_outputAVStream );
Expand All @@ -49,13 +45,61 @@ size_t OutputStream::getNbFrames() const
return _outputAVStream.nb_frames;
}

int OutputStream::getStreamPTS() const
{
const AVFrac& outputPTS = _outputAVStream.pts;
return ( outputPTS.val + ( outputPTS.num / outputPTS.den ) );
}

IOutputStream::EWrappingStatus OutputStream::wrap( const CodedData& data )
{
// If stream PTS will be generated at rewrap time
if( ! _isPTSGenerated && (data.getAVPacket().pts == 0 || data.getAVPacket().pts == AV_NOPTS_VALUE) && data.getAVPacket().dts == AV_NOPTS_VALUE )
{
LOG_WARN( "PTS of output stream " << _streamIndex << " is generated at rewrap time." )
_isPTSGenerated = true;
}

// wrap packet
IOutputStream::EWrappingStatus status = _outputFile.wrap( data, _streamIndex );

// append duration of the packet to the stream
_wrappedPacketsDuration += data.getAVPacket().duration;
// Store duration of the last packet wrapped
if( data.getAVPacket().duration != 0 && data.getAVPacket().duration != _lastWrappedPacketDuration )
_lastWrappedPacketDuration = data.getAVPacket().duration;

// Append duration of the packet to the stream
if( data.getAVPacket().duration )
_wrappedPacketsDuration += data.getAVPacket().duration;
else
{
switch( _outputAVStream.codec->codec_type )
{
case AVMEDIA_TYPE_VIDEO:
{
_wrappedPacketsDuration += _lastWrappedPacketDuration;
break;
}
case AVMEDIA_TYPE_AUDIO:
{
Rational audioPacketDuration;
audioPacketDuration.num = 0;
audioPacketDuration.den = 0;
const int frame_size = av_get_audio_frame_duration(_outputAVStream.codec, data.getSize());
if( frame_size <= 0 || _outputAVStream.codec->sample_rate <= 0 )
break;
audioPacketDuration.num = frame_size;
audioPacketDuration.den = _outputAVStream.codec->sample_rate;
_wrappedPacketsDuration += av_rescale(
1,
audioPacketDuration.num * (int64_t)_outputAVStream.time_base.den * _outputAVStream.codec->ticks_per_frame,
audioPacketDuration.den * (int64_t)_outputAVStream.time_base.num
);
break;
}
default:
break;
}
}

return status;
}
Expand Down
16 changes: 10 additions & 6 deletions src/AvTranscoder/stream/OutputStream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ class AvExport OutputStream : public IOutputStream
size_t getStreamIndex() const { return _streamIndex; }
float getStreamDuration() const;
size_t getNbFrames() const; ///< If audio stream, returns number of packets
int getStreamPTS() const; ///< Get current AVStream PTS

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

private:
Expand All @@ -27,12 +29,14 @@ class AvExport OutputStream : public IOutputStream

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

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

}
Expand Down
15 changes: 7 additions & 8 deletions src/AvTranscoder/transcoder/StreamTranscoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,15 +319,14 @@ void StreamTranscoder::preProcessCodecLatency()
{
if( ! _outputEncoder )
{
std::stringstream os;
os << "No output encoder found for stream ";
std::stringstream msg;
msg << "No encoder found for input stream ";
if( getProcessCase() == eProcessCaseGenerator )
os << "generator";
msg << "generator";
else
os << _inputStream->getStreamIndex();
os << ": will not preProcessCodecLatency.";
LOG_INFO( os.str() )

msg << _inputStream->getStreamIndex();
msg << ": will not preProcessCodecLatency.";
LOG_WARN( msg.str() )
return;
}

Expand Down Expand Up @@ -408,7 +407,7 @@ bool StreamTranscoder::processRewrap()
LOG_DEBUG( "StreamTranscoder::processRewrap" )

// if switched to generator, process frame
if( _currentDecoder == _generator )
if( _currentDecoder && _currentDecoder == _generator )
{
return processTranscode();
}
Expand Down
8 changes: 4 additions & 4 deletions src/AvTranscoder/transcoder/StreamTranscoder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ class AvExport StreamTranscoder
*/
float getDuration() const;

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

/// Returns a reference to the object which transforms the decoded data
ITransform& getTransform() const { return *_transform; }
Expand Down
16 changes: 10 additions & 6 deletions src/AvTranscoder/transcoder/Transcoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,14 @@ ProcessStat Transcoder::process( IProgress& progress )

preProcessCodecLatency();

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

size_t frame = 0;
bool frameProcessed = true;
while( frameProcessed )
{
const double progressDuration = _outputFile.getStream( 0 ).getStreamDuration();
const float progressDuration = _outputFile.getStream( 0 ).getStreamDuration();

// check if JobStatusCancel
if( progress.progress( ( progressDuration > outputDuration ) ? outputDuration : progressDuration, outputDuration ) == eJobStatusCancel )
Expand Down Expand Up @@ -528,11 +528,15 @@ void Transcoder::fillProcessStat( ProcessStat& processStat )
case AVMEDIA_TYPE_VIDEO:
{
VideoStat videoStat( stream.getStreamDuration(), stream.getNbFrames() );
const AVCodecContext& encoderContext = _streamTranscoders.at( streamIndex )->getEncoder().getCodec().getAVCodecContext();
if( encoderContext.coded_frame && ( encoderContext.flags & CODEC_FLAG_PSNR) )
IEncoder* encoder = _streamTranscoders.at( streamIndex )->getEncoder();
if( encoder )
{
videoStat._quality = encoderContext.coded_frame->quality;
videoStat._psnr = VideoStat::psnr( encoderContext.coded_frame->error[0] / ( encoderContext.width * encoderContext.height * 255.0 * 255.0 ) );
const AVCodecContext& encoderContext = encoder->getCodec().getAVCodecContext();
if( encoderContext.coded_frame && ( encoderContext.flags & CODEC_FLAG_PSNR) )
{
videoStat._quality = encoderContext.coded_frame->quality;
videoStat._psnr = VideoStat::psnr( encoderContext.coded_frame->error[0] / ( encoderContext.width * encoderContext.height * 255.0 * 255.0 ) );
}
}
processStat.addVideoStat( streamIndex, videoStat );
break;
Expand Down
4 changes: 4 additions & 0 deletions test/pyTest/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from pyAvTranscoder import avtranscoder as av

av.preloadCodecsAndFormats()
av.Logger.setLogLevel(av.AV_LOG_WARNING)
Loading
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