From 66ce1cbcb674b10e589f7b7a7b1f60bf6bc41629 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 29 Feb 2016 17:15:32 +0100 Subject: [PATCH 1/8] pyrewrap app: removed unused local variable logger --- app/pyRewrap/pyrewrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/pyRewrap/pyrewrap.py b/app/pyRewrap/pyrewrap.py index b701b50e..101e1d3f 100644 --- a/app/pyRewrap/pyrewrap.py +++ b/app/pyRewrap/pyrewrap.py @@ -48,7 +48,7 @@ exit(1) # setup avtranscoder -logger = av.Logger().setLogLevel(av.AV_LOG_QUIET) +av.Logger().setLogLevel(av.AV_LOG_QUIET) av.preloadCodecsAndFormats() # create input file From 0589b91b95af6bbe499d9613c5f89077c3535b0a Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 29 Feb 2016 17:16:03 +0100 Subject: [PATCH 2/8] pythumbnail app: removed unused local variable logger --- app/pyThumbnail/pythumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/pyThumbnail/pythumbnail.py b/app/pyThumbnail/pythumbnail.py index ca7eeb64..fa60fa08 100644 --- a/app/pyThumbnail/pythumbnail.py +++ b/app/pyThumbnail/pythumbnail.py @@ -53,7 +53,7 @@ # setup avtranscoder -logger = av.Logger().setLogLevel(av.AV_LOG_QUIET) +av.Logger().setLogLevel(av.AV_LOG_QUIET) av.preloadCodecsAndFormats() # create input file From 8d4cd43e06f0214a0e6e6410866419dc23cc0a8d Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 29 Feb 2016 17:16:52 +0100 Subject: [PATCH 3/8] pythumbnail app: removed unnecessary semicolons --- app/pyThumbnail/pythumbnail.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/pyThumbnail/pythumbnail.py b/app/pyThumbnail/pythumbnail.py index fa60fa08..63121660 100644 --- a/app/pyThumbnail/pythumbnail.py +++ b/app/pyThumbnail/pythumbnail.py @@ -97,10 +97,10 @@ # create transcoder transcoder = av.Transcoder( outputFile ) -transcoder.add( outputStream ); +transcoder.add( outputStream ) # launch process -outputFile.beginWrap(); -transcoder.preProcessCodecLatency(); -transcoder.processFrame(); -outputFile.endWrap(); +outputFile.beginWrap() +transcoder.preProcessCodecLatency() +transcoder.processFrame() +outputFile.endWrap() From ebf3d4efda171ce3b5625f76a1b4db2e1edaeef9 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 29 Feb 2016 17:17:44 +0100 Subject: [PATCH 4/8] InputStream: updated log messages when read next packets --- src/AvTranscoder/file/InputFile.cpp | 2 +- src/AvTranscoder/stream/InputStream.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AvTranscoder/file/InputFile.cpp b/src/AvTranscoder/file/InputFile.cpp index 439a8ced..93dcaddb 100644 --- a/src/AvTranscoder/file/InputFile.cpp +++ b/src/AvTranscoder/file/InputFile.cpp @@ -80,7 +80,7 @@ bool InputFile::readNextPacket(CodedData& data, const size_t streamIndex) const int packetStreamIndex = data.getAVPacket().stream_index; if(packetStreamIndex == (int)streamIndex) { - LOG_DEBUG("Get a packet data of the stream " << streamIndex) + LOG_DEBUG("Get a packet from stream " << streamIndex) nextPacketFound = true; } // else add the packet data to the stream cache diff --git a/src/AvTranscoder/stream/InputStream.cpp b/src/AvTranscoder/stream/InputStream.cpp index a23cfe87..8f465694 100644 --- a/src/AvTranscoder/stream/InputStream.cpp +++ b/src/AvTranscoder/stream/InputStream.cpp @@ -58,14 +58,14 @@ bool InputStream::readNextPacket(CodedData& data) // if packet is already cached if(!_streamCache.empty()) { - LOG_DEBUG("Get packet data of stream " << _streamIndex << " from the cache") + LOG_DEBUG("Get packet of '" << _inputFile->getFilename() << "' (stream " << _streamIndex << ") from the cache") data.copyData(_streamCache.front().getData(), _streamCache.front().getSize()); _streamCache.pop(); } // else read next packet else { - LOG_DEBUG("Read next packet") + LOG_DEBUG("Read next packet of '" << _inputFile->getFilename() << "' (stream " << _streamIndex << ")") return _inputFile->readNextPacket(data, _streamIndex) && _streamCache.empty(); } From 06ec0b693a49fc13ebac9ed3df6c56c05e7dac9d Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 29 Feb 2016 17:22:54 +0100 Subject: [PATCH 5/8] Video/Audio decoders: fixed decoding when codec capabilities has CODEC_CAP_DELAY Fix #231 --- src/AvTranscoder/decoder/AudioDecoder.cpp | 4 +++- src/AvTranscoder/decoder/VideoDecoder.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/AvTranscoder/decoder/AudioDecoder.cpp b/src/AvTranscoder/decoder/AudioDecoder.cpp index fa7da88a..9c8695fd 100644 --- a/src/AvTranscoder/decoder/AudioDecoder.cpp +++ b/src/AvTranscoder/decoder/AudioDecoder.cpp @@ -89,13 +89,15 @@ bool AudioDecoder::decodeNextFrame(Frame& frameBuffer) const bool nextPacketRead = _inputStream->readNextPacket(data); // if error or end of file - if(!nextPacketRead) + if(!nextPacketRead && !decodeNextFrame) { data.clear(); return false; } // decoding + // @note could be called several times to return the remaining frames (last call with an empty packet) + // @see CODEC_CAP_DELAY int ret = avcodec_decode_audio4(&_inputStream->getAudioCodec().getAVCodecContext(), &frameBuffer.getAVFrame(), &got_frame, &data.getAVPacket()); if(ret < 0) diff --git a/src/AvTranscoder/decoder/VideoDecoder.cpp b/src/AvTranscoder/decoder/VideoDecoder.cpp index 72e5759e..5affcb56 100644 --- a/src/AvTranscoder/decoder/VideoDecoder.cpp +++ b/src/AvTranscoder/decoder/VideoDecoder.cpp @@ -87,13 +87,15 @@ bool VideoDecoder::decodeNextFrame(Frame& frameBuffer) const bool nextPacketRead = _inputStream->readNextPacket(data); // if error or end of file - if(!nextPacketRead) + if(!nextPacketRead && !decodeNextFrame) { data.clear(); return false; } // decoding + // @note could be called several times to return the remaining frames (last call with an empty packet) + // @see CODEC_CAP_DELAY const int ret = avcodec_decode_video2(&_inputStream->getVideoCodec().getAVCodecContext(), &frameBuffer.getAVFrame(), &got_frame, &data.getAVPacket()); if(ret < 0) From d8f283cdc38dd4a1d4bb527c43f183fbe6525ad7 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 29 Feb 2016 17:43:00 +0100 Subject: [PATCH 6/8] Transcoder: call processFrame before checking the end of process * Because in some cases, the duration of input is 0 and we would like to process at least one frame. * Fix #231 --- src/AvTranscoder/transcoder/Transcoder.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 47e5f2a7..247fc5b2 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -289,6 +289,10 @@ ProcessStat Transcoder::process(IProgress& progress) bool frameProcessed = true; while(frameProcessed) { + LOG_DEBUG("Process frame " << frame) + frameProcessed = processFrame(); + ++frame; + const float progressDuration = getCurrentOutputDuration(); // check if JobStatusCancel @@ -306,10 +310,6 @@ ProcessStat Transcoder::process(IProgress& progress) << progressDuration << "s) is equal or upper than " << expectedOutputDuration << "s.") break; } - - LOG_DEBUG("Process frame " << frame) - frameProcessed = processFrame(); - ++frame; } _outputFile.endWrap(); From 914bce1b879c75716a09a9303dc47eaae76102f6 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 29 Feb 2016 17:43:48 +0100 Subject: [PATCH 7/8] properties: display nan values as N/A Same behavior as ffprobe. --- src/AvTranscoder/properties/util.cpp | 26 ++++++++++++++++++++++++++ src/AvTranscoder/properties/util.hpp | 6 ++++++ 2 files changed, 32 insertions(+) diff --git a/src/AvTranscoder/properties/util.cpp b/src/AvTranscoder/properties/util.cpp index 058b8759..b236bd6b 100644 --- a/src/AvTranscoder/properties/util.cpp +++ b/src/AvTranscoder/properties/util.cpp @@ -1,5 +1,9 @@ #include "util.hpp" +extern "C" { +#include +} + #include namespace avtranscoder @@ -8,6 +12,28 @@ namespace avtranscoder namespace detail { +template <> +void add(PropertyVector& propertyVector, const std::string& key, const size_t& value) +{ + std::stringstream ss; + if(value == (size_t)AV_NOPTS_VALUE) + ss << "N/A"; + else + ss << value; + add(propertyVector, key, ss.str()); +} + +template <> +void add(PropertyVector& propertyVector, const std::string& key, const float& value) +{ + std::stringstream ss; + if(value <= AV_NOPTS_VALUE || value >= AV_NOPTS_VALUE) + ss << "N/A"; + else + ss << value; + add(propertyVector, key, ss.str()); +} + template <> void add(PropertyVector& propertyVector, const std::string& key, const std::string& value) { diff --git a/src/AvTranscoder/properties/util.hpp b/src/AvTranscoder/properties/util.hpp index 4087c09d..411fd01c 100644 --- a/src/AvTranscoder/properties/util.hpp +++ b/src/AvTranscoder/properties/util.hpp @@ -45,6 +45,12 @@ void add(PropertyVector& propertyVector, const std::string& key, const T& value) add(propertyVector, key, ss.str()); } +template <> +void add(PropertyVector& propertyVector, const std::string& key, const size_t& value); + +template <> +void add(PropertyVector& propertyVector, const std::string& key, const float& value); + template <> void add(PropertyVector& propertyVector, const std::string& key, const std::string& value); From 38b4f4e8f6baf95bab2bb0324db8de18e1d42fa5 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 29 Feb 2016 17:44:53 +0100 Subject: [PATCH 8/8] pyTest: added testTranscoderTranscodeImage * Test with png. * Test with jpg. --- test/pyTest/testTranscoderTranscodeImage.py | 75 +++++++++++++++++++++ tools/appveyor/python.nosetests.bat | 2 + tools/travis/python.nosetests.sh | 2 + 3 files changed, 79 insertions(+) create mode 100644 test/pyTest/testTranscoderTranscodeImage.py diff --git a/test/pyTest/testTranscoderTranscodeImage.py b/test/pyTest/testTranscoderTranscodeImage.py new file mode 100644 index 00000000..5e1db9b9 --- /dev/null +++ b/test/pyTest/testTranscoderTranscodeImage.py @@ -0,0 +1,75 @@ +import os + +# Check if environment is setup to run the tests +if os.environ.get('AVTRANSCODER_TEST_IMAGE_PNG_FILE') is None or \ + os.environ.get('AVTRANSCODER_TEST_IMAGE_JPG_FILE') is None: + from nose.plugins.skip import SkipTest + raise SkipTest("Need to define environment variables " + "AVTRANSCODER_TEST_IMAGE_PNG_FILE and " + "AVTRANSCODER_TEST_IMAGE_JPG_FILE") + +from nose.tools import * + +from pyAvTranscoder import avtranscoder as av + + +def testTranscodePngToMjpeg(): + """ + Transcode one image (to mjpeg). + """ + inputFileName = os.environ['AVTRANSCODER_TEST_IMAGE_PNG_FILE'] + outputFileName = "testTranscodePngToMjpeg.jpg" + + ouputFile = av.OutputFile( outputFileName ) + transcoder = av.Transcoder( ouputFile ) + + inputFile = av.InputFile( inputFileName ) + src_videoStream = inputFile.getProperties().getVideoProperties()[0] + videoStreamIndex = src_videoStream.getStreamIndex() + transcoder.add( inputFileName, videoStreamIndex, "mjpeg" ) + + progress = av.ConsoleProgress() + processStat = transcoder.process( progress ) + + # check process stat returned + videoStat = processStat.getVideoStat(0) + assert_equals(1, videoStat.getNbFrames()) + + # get dst file of transcode + dst_inputFile = av.InputFile( outputFileName ) + dst_properties = dst_inputFile.getProperties() + dst_videoStream = dst_properties.getVideoProperties()[0] + + assert_equals( "mjpeg", dst_videoStream.getCodecName() ) + assert_equals( "yuvj420p", dst_videoStream.getPixelProperties().getPixelName() ) + + +def testTranscodeJpgToMjpeg(): + """ + Transcode one image (to mjpeg). + """ + inputFileName = os.environ['AVTRANSCODER_TEST_IMAGE_JPG_FILE'] + outputFileName = "testTranscodeJpgToMjpeg.jpg" + + ouputFile = av.OutputFile( outputFileName ) + transcoder = av.Transcoder( ouputFile ) + + inputFile = av.InputFile( inputFileName ) + src_videoStream = inputFile.getProperties().getVideoProperties()[0] + videoStreamIndex = src_videoStream.getStreamIndex() + transcoder.add( inputFileName, videoStreamIndex, "mjpeg" ) + + progress = av.ConsoleProgress() + processStat = transcoder.process( progress ) + + # check process stat returned + videoStat = processStat.getVideoStat(0) + assert_equals(1, videoStat.getNbFrames()) + + # get dst file of transcode + dst_inputFile = av.InputFile( outputFileName ) + dst_properties = dst_inputFile.getProperties() + dst_videoStream = dst_properties.getVideoProperties()[0] + + assert_equals( "mjpeg", dst_videoStream.getCodecName() ) + assert_equals( "yuvj420p", dst_videoStream.getPixelProperties().getPixelName() ) diff --git a/tools/appveyor/python.nosetests.bat b/tools/appveyor/python.nosetests.bat index d9904512..cbf6f98c 100755 --- a/tools/appveyor/python.nosetests.bat +++ b/tools/appveyor/python.nosetests.bat @@ -16,6 +16,8 @@ set AVTRANSCODER_TEST_VIDEO_MP4_FILE=%PWD%\avTranscoder-data\video\BigBuckBunny\ set AVTRANSCODER_TEST_VIDEO_MOV_FILE=%PWD%\avTranscoder-data\video\BigBuckBunny\BigBuckBunny_640p_h264.mov set AVTRANSCODER_TEST_AUDIO_WAVE_FILE=%PWD%\avTranscoder-data\audio\frequenciesPerChannel.wav set AVTRANSCODER_TEST_AUDIO_MOV_FILE=%PWD%\avTranscoder-data\video\BigBuckBunny\BigBuckBunny_1080p_5_1.mov +set AVTRANSCODER_TEST_IMAGE_PNG_FILE=%PWD%\avTranscoder-data\image\BigBuckBunny\bbb-splash.thumbnail.png +set AVTRANSCODER_TEST_IMAGE_JPG_FILE=%PWD%\avTranscoder-data\image\BigBuckBunny\title_anouncement.thumbnail.jpg :: Launch tests cd test\pyTest diff --git a/tools/travis/python.nosetests.sh b/tools/travis/python.nosetests.sh index bcd06132..d145612e 100755 --- a/tools/travis/python.nosetests.sh +++ b/tools/travis/python.nosetests.sh @@ -14,6 +14,8 @@ export AVTRANSCODER_TEST_VIDEO_MP4_FILE=`pwd`/avTranscoder-data/video/BigBuckBun export AVTRANSCODER_TEST_VIDEO_MOV_FILE=`pwd`/avTranscoder-data/video/BigBuckBunny/BigBuckBunny_640p_h264.mov export AVTRANSCODER_TEST_AUDIO_WAVE_FILE=`pwd`/avTranscoder-data/audio/frequenciesPerChannel.wav export AVTRANSCODER_TEST_AUDIO_MOV_FILE=`pwd`/avTranscoder-data/video/BigBuckBunny/BigBuckBunny_1080p_5_1.mov +export AVTRANSCODER_TEST_IMAGE_PNG_FILE=`pwd`/avTranscoder-data/image/BigBuckBunny/bbb-splash.thumbnail.png +export AVTRANSCODER_TEST_IMAGE_JPG_FILE=`pwd`/avTranscoder-data/image/BigBuckBunny/title_anouncement.thumbnail.jpg # Launch tests nosetests ${TRAVIS_BUILD_DIR}/test/pyTest --with-coverage