Skip to content

Commit f6bfdcd

Browse files
committed
Merge pull request #239 from cchampet/dev_readerProcessGenerator2
reader: process with a generator
2 parents 1b8bce2 + 1a894e3 commit f6bfdcd

File tree

10 files changed

+178
-14
lines changed

10 files changed

+178
-14
lines changed

src/AvTranscoder/data/decoded/Frame.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ class AvExport Frame
4343
int* getLineSize() const { return _frame->linesize; }
4444

4545
/**
46-
* @brief Copy the data of the given Frame.
47-
*/
46+
* @brief Copy the data of the given Frame.
47+
* @note This function does not allocate anything: the current frame must be already initialized and
48+
* allocated with the same parameters as the given frame, to be ready for memcpy instructions.
49+
*/
4850
void copyData(const Frame& frameToRef);
4951

5052
/**

src/AvTranscoder/decoder/AudioGenerator.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#include "AudioGenerator.hpp"
22

3+
#include <AvTranscoder/util.hpp>
4+
5+
#include <sstream>
6+
37
namespace avtranscoder
48
{
59

@@ -42,13 +46,26 @@ bool AudioGenerator::decodeNextFrame(Frame& frameBuffer)
4246
{
4347
AudioFrame& audioBuffer = static_cast<AudioFrame&>(frameBuffer);
4448
_silent = new AudioFrame(audioBuffer.desc());
49+
50+
std::stringstream msg;
51+
msg << "Generate a silence with the following features:" << std::endl;
52+
msg << "sample rate = " << _silent->getSampleRate() << std::endl;
53+
msg << "number of channels = " << _silent->getNbChannels() << std::endl;
54+
msg << "sample format = " << getSampleFormatName(_silent->getSampleFormat()) << std::endl;
55+
msg << "number of samples per channel = " << _silent->getNbSamplesPerChannel() << std::endl;
56+
LOG_INFO(msg.str())
57+
58+
// Set the number of samples of silence to the number of samples of the given frame
59+
// (which was allocated to expect this number of samples).
60+
_silent->setNbSamplesPerChannel(frameBuffer.getAVFrame().nb_samples);
4561
}
46-
frameBuffer.getAVFrame().nb_samples = _silent->getAVFrame().nb_samples;
62+
LOG_DEBUG("Copy data of the silence when decode next frame")
4763
frameBuffer.copyData(*_silent);
4864
}
4965
// Take audio frame from _inputFrame
5066
else
5167
{
68+
LOG_DEBUG("Copy data of the audio specified when decode next frame")
5269
frameBuffer.copyData(*_inputFrame);
5370
}
5471
return true;

src/AvTranscoder/decoder/VideoGenerator.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <AvTranscoder/util.hpp>
44
#include <AvTranscoder/transform/VideoTransform.hpp>
55

6+
#include <sstream>
7+
68
namespace avtranscoder
79
{
810

@@ -51,6 +53,13 @@ bool VideoGenerator::decodeNextFrame(Frame& frameBuffer)
5153
// Generate the black image only once
5254
if(!_blackImage)
5355
{
56+
std::stringstream msg;
57+
msg << "Generate a black image with the following features:" << std::endl;
58+
msg << "width = " << _frameDesc._width << std::endl;
59+
msg << "height = " << _frameDesc._height << std::endl;
60+
msg << "pixel format = rgb24" << std::endl;
61+
LOG_INFO(msg.str())
62+
5463
VideoFrame& imageBuffer = static_cast<VideoFrame&>(frameBuffer);
5564

5665
// Input of convert
@@ -68,11 +77,13 @@ bool VideoGenerator::decodeNextFrame(Frame& frameBuffer)
6877
VideoTransform videoTransform;
6978
videoTransform.convert(intermediateBuffer, *_blackImage);
7079
}
80+
LOG_DEBUG("Copy data of the black image when decode next frame")
7181
frameBuffer.copyData(*_blackImage);
7282
}
7383
// Take image from _inputFrame
7484
else
7585
{
86+
LOG_DEBUG("Copy data of the image specified when decode next frame")
7687
frameBuffer.copyData(*_inputFrame);
7788
}
7889
return true;

src/AvTranscoder/reader/AudioReader.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <AvTranscoder/util.hpp>
44
#include <AvTranscoder/decoder/AudioDecoder.hpp>
5+
#include <AvTranscoder/decoder/AudioGenerator.hpp>
56
#include <AvTranscoder/data/decoded/AudioFrame.hpp>
67
#include <AvTranscoder/transform/AudioTransform.hpp>
78
#include <AvTranscoder/progress/NoDisplayProgress.hpp>
@@ -42,6 +43,9 @@ void AudioReader::init()
4243
_decoder = new AudioDecoder(_inputFile->getStream(_streamIndex));
4344
_decoder->setupDecoder();
4445

46+
// generator
47+
_generator = new AudioGenerator();
48+
4549
// create transform
4650
_transform = new AudioTransform();
4751

@@ -57,6 +61,7 @@ void AudioReader::init()
5761
AudioReader::~AudioReader()
5862
{
5963
delete _decoder;
64+
delete _generator;
6065
delete _srcFrame;
6166
delete _dstFrame;
6267
delete _transform;

src/AvTranscoder/reader/IReader.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ IReader::IReader(const std::string& filename, const size_t streamIndex, const in
1616
, _channelIndex(channelIndex)
1717
, _currentFrame(-1)
1818
, _inputFileAllocated(true)
19+
, _continueWithGenerator(false)
1920
{
2021
_inputFile = new InputFile(filename);
2122
}
@@ -31,6 +32,7 @@ IReader::IReader(InputFile& inputFile, const size_t streamIndex, const int chann
3132
, _channelIndex(channelIndex)
3233
, _currentFrame(-1)
3334
, _inputFileAllocated(false)
35+
, _continueWithGenerator(false)
3436
{
3537
}
3638

@@ -53,6 +55,7 @@ Frame* IReader::readPrevFrame()
5355
Frame* IReader::readFrameAt(const size_t frame)
5456
{
5557
assert(_decoder != NULL);
58+
assert(_generator != NULL);
5659
assert(_transform != NULL);
5760
assert(_srcFrame != NULL);
5861
assert(_dstFrame != NULL);
@@ -70,10 +73,19 @@ Frame* IReader::readFrameAt(const size_t frame)
7073
decodingStatus = _decoder->decodeNextFrame(*_srcFrame, _channelIndex);
7174
else
7275
decodingStatus = _decoder->decodeNextFrame(*_srcFrame);
76+
// if decoding failed
7377
if(!decodingStatus)
7478
{
75-
_dstFrame->clear();
76-
return _dstFrame;
79+
// generate data (ie silence or black)
80+
if(_continueWithGenerator)
81+
{
82+
_generator->decodeNextFrame(*_srcFrame);
83+
}
84+
// or return NULL
85+
else
86+
{
87+
return NULL;
88+
}
7789
}
7890
// transform
7991
_transform->convert(*_srcFrame, *_dstFrame);

src/AvTranscoder/reader/IReader.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,20 @@ class AvExport IReader
3535

3636
/**
3737
* @return Get next frame after decoding
38+
* @see readFrameAt
3839
*/
3940
Frame* readNextFrame();
4041

4142
/**
4243
* @return Get previous frame after decoding
44+
* @see readFrameAt
4345
*/
4446
Frame* readPrevFrame();
4547

4648
/**
4749
* @return Get indicated frame after decoding
50+
* @warn Returns NULL if there is no more frame to read.
51+
* @see continueWithGenerator
4852
*/
4953
Frame* readFrameAt(const size_t frame);
5054

@@ -53,10 +57,17 @@ class AvExport IReader
5357
*/
5458
const StreamProperties* getSourceProperties() const { return _streamProperties; }
5559

60+
/**
61+
* @brief Set the reader state to generate data (ie silence or black) when there is no more data to decode.
62+
* @note By default, the reader returns an empty frame.
63+
*/
64+
void continueWithGenerator(const bool continueWithGenerator = true) { _continueWithGenerator = continueWithGenerator; }
65+
5666
protected:
5767
InputFile* _inputFile;
5868
const StreamProperties* _streamProperties;
5969
IDecoder* _decoder;
70+
IDecoder* _generator;
6071

6172
Frame* _srcFrame;
6273
Frame* _dstFrame;
@@ -69,6 +80,7 @@ class AvExport IReader
6980
private:
7081
int _currentFrame; ///< The current decoded frame.
7182
bool _inputFileAllocated; ///< Does the InputFile is held by the class or not (depends on the constructor called)
83+
bool _continueWithGenerator; ///< If there is no more data to decode, complete with generated data
7284
};
7385
}
7486

src/AvTranscoder/reader/VideoReader.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "VideoReader.hpp"
22

33
#include <AvTranscoder/decoder/VideoDecoder.hpp>
4+
#include <AvTranscoder/decoder/VideoGenerator.hpp>
45
#include <AvTranscoder/data/decoded/VideoFrame.hpp>
56
#include <AvTranscoder/transform/VideoTransform.hpp>
67
#include <AvTranscoder/progress/NoDisplayProgress.hpp>
@@ -41,6 +42,11 @@ void VideoReader::init()
4142
_decoder = new VideoDecoder(_inputFile->getStream(_streamIndex));
4243
_decoder->setupDecoder();
4344

45+
// generator
46+
VideoGenerator* generator = new VideoGenerator();
47+
generator->setVideoFrameDesc(_inputFile->getStream(_streamIndex).getVideoCodec().getVideoFrameDesc());
48+
_generator = generator;
49+
4450
// create transform
4551
_transform = new VideoTransform();
4652

@@ -56,6 +62,7 @@ void VideoReader::init()
5662
VideoReader::~VideoReader()
5763
{
5864
delete _decoder;
65+
delete _generator;
5966
delete _srcFrame;
6067
delete _dstFrame;
6168
delete _transform;

test/pyTest/testReader.py

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ def testVideoReaderCreateNewInputFile():
2424
# read all frames and check their size
2525
for i in xrange(0, reader.getSourceVideoProperties().getNbFrames()):
2626
frame = av.VideoFrame(reader.readNextFrame())
27-
assert_equals( frame.getSize(), reader.getOutputWidth() * reader.getOutputHeight() * reader.getOutputNbComponents() )
27+
bytesPerPixel = reader.getOutputBitDepth() / 8
28+
assert_equals( frame.getSize(), reader.getOutputWidth() * reader.getOutputHeight() * bytesPerPixel )
2829

29-
# check if the next frame is empty
30-
frame = av.VideoFrame(reader.readNextFrame())
31-
assert_equals( frame.getSize(), 0 )
30+
# check if there is no next frame
31+
frame = reader.readNextFrame()
32+
assert_equals( reader.readNextFrame(), None )
3233

3334

3435
def testVideoReaderReferenceInputFile():
@@ -43,11 +44,11 @@ def testVideoReaderReferenceInputFile():
4344
# read all frames and check their size
4445
for i in xrange(0, reader.getSourceVideoProperties().getNbFrames()):
4546
frame = av.VideoFrame(reader.readNextFrame())
46-
assert_equals( frame.getSize(), reader.getOutputWidth() * reader.getOutputHeight() * reader.getOutputNbComponents() )
47+
bytesPerPixel = reader.getOutputBitDepth() / 8
48+
assert_equals( frame.getSize(), reader.getOutputWidth() * reader.getOutputHeight() * bytesPerPixel )
4749

48-
# check if the next frame is empty
49-
frame = av.VideoFrame(reader.readNextFrame())
50-
assert_equals( frame.getSize(), 0 )
50+
# check if there is no next frame
51+
assert_equals( reader.readNextFrame(), None )
5152

5253

5354
def testAudioReaderChannelsExtraction():
@@ -74,3 +75,59 @@ def testAudioReaderChannelsExtraction():
7475
sizeOfFrameWithOneChannels = frame.getSize()
7576

7677
assert_equals( sizeOfFrameWithAllChannels / nbChannels, sizeOfFrameWithOneChannels )
78+
79+
80+
def testVideoReaderWithGenerator():
81+
"""
82+
Read a video stream with the VideoReader.
83+
When there is no more data to decode, switch to a generator and process some frames.
84+
"""
85+
inputFileName = os.environ['AVTRANSCODER_TEST_VIDEO_AVI_FILE']
86+
reader = av.VideoReader(inputFileName)
87+
88+
# read all frames and check their size
89+
for i in xrange(0, reader.getSourceVideoProperties().getNbFrames()):
90+
frame = av.VideoFrame(reader.readNextFrame())
91+
bytesPerPixel = reader.getOutputBitDepth() / 8
92+
assert_equals( frame.getSize(), reader.getOutputWidth() * reader.getOutputHeight() * bytesPerPixel )
93+
94+
# check if there is no next frame
95+
assert_equals( reader.readNextFrame(), None )
96+
97+
# generate 10 frames of black
98+
reader.continueWithGenerator()
99+
for i in xrange(0, 9):
100+
frame = av.VideoFrame(reader.readNextFrame())
101+
bytesPerPixel = reader.getOutputBitDepth() / 8
102+
assert_equals( frame.getSize(), reader.getOutputWidth() * reader.getOutputHeight() * bytesPerPixel )
103+
104+
105+
def testAudioReaderWithGenerator():
106+
"""
107+
Read an audio stream with the AudioReader.
108+
When there is no more data to decode, switch to a generator and process some frames.
109+
"""
110+
inputFileName = os.environ['AVTRANSCODER_TEST_AUDIO_WAVE_FILE']
111+
inputFile = av.InputFile(inputFileName)
112+
reader = av.AudioReader(inputFile)
113+
114+
# read all frames and check their size
115+
while True:
116+
frame = reader.readNextFrame()
117+
if not frame:
118+
break
119+
frame = av.AudioFrame(frame)
120+
nbSamplesPerChannel = frame.getNbSamplesPerChannel()
121+
bytesPerSample = 2
122+
assert_equals( frame.getSize(), reader.getOutputNbChannels() * nbSamplesPerChannel * bytesPerSample )
123+
124+
# check if there is no next frame
125+
assert_equals( reader.readNextFrame(), None )
126+
127+
# generate 10 frames of silence
128+
reader.continueWithGenerator()
129+
for i in xrange(0, 9):
130+
frame = av.AudioFrame(reader.readNextFrame())
131+
nbSamplesPerChannel = frame.getNbSamplesPerChannel()
132+
bytesPerSample = 2
133+
assert_equals( frame.getSize(), reader.getOutputNbChannels() * nbSamplesPerChannel * bytesPerSample )

test/pyTest/testTranscoderTranscodeAudioWave.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def testTranscodeWave24b48k5_1():
4343
assert_equals( 48000, dst_audioStream.getSampleRate() )
4444
assert_equals( 6, dst_audioStream.getNbChannels() )
4545

46+
4647
def testTranscodeWave24b48kstereo():
4748
"""
4849
Transcode one audio stream (profile wave24b48kstereo).
@@ -76,6 +77,7 @@ def testTranscodeWave24b48kstereo():
7677
assert_equals( 48000, dst_audioStream.getSampleRate() )
7778
assert_equals( 2, dst_audioStream.getNbChannels() )
7879

80+
7981
def testTranscodeWave24b48kmono():
8082
"""
8183
Transcode one audio stream (profile wave24b48kmono).
@@ -109,6 +111,7 @@ def testTranscodeWave24b48kmono():
109111
assert_equals( 48000, dst_audioStream.getSampleRate() )
110112
assert_equals( 1, dst_audioStream.getNbChannels() )
111113

114+
112115
def testTranscodeWave16b48kmono():
113116
"""
114117
Transcode one audio stream (profile wave16b48kmono).
@@ -141,3 +144,40 @@ def testTranscodeWave16b48kmono():
141144
assert_equals( "signed 16 bits", dst_audioStream.getSampleFormatLongName() )
142145
assert_equals( 48000, dst_audioStream.getSampleRate() )
143146
assert_equals( 1, dst_audioStream.getNbChannels() )
147+
148+
149+
def testTranscodeWave16b48kmonoWithSilence():
150+
"""
151+
Transcode one audio stream (profile wave16b48kmono).
152+
Complete with silence.
153+
"""
154+
inputFileName = os.environ['AVTRANSCODER_TEST_AUDIO_WAVE_FILE']
155+
outputFileName = "testTranscodeWave16b48kmonoWithSilence.wav"
156+
outputDuration = 50
157+
158+
ouputFile = av.OutputFile( outputFileName )
159+
transcoder = av.Transcoder( ouputFile )
160+
transcoder.setProcessMethod( av.eProcessMethodBasedOnDuration, 0, outputDuration )
161+
162+
inputFile = av.InputFile( inputFileName )
163+
src_audioStream = inputFile.getProperties().getAudioProperties()[0]
164+
audioStreamIndex = src_audioStream.getStreamIndex()
165+
transcoder.add( inputFileName, audioStreamIndex, "wave16b48kmono" )
166+
167+
progress = av.ConsoleProgress()
168+
processStat = transcoder.process( progress )
169+
170+
# check process stat returned
171+
audioStat = processStat.getAudioStat(0)
172+
assert_almost_equals( audioStat.getDuration(), outputDuration, delta=0.01 )
173+
174+
# get dst file of transcode
175+
dst_inputFile = av.InputFile( outputFileName )
176+
dst_properties = dst_inputFile.getProperties()
177+
dst_audioStream = dst_properties.getAudioProperties()[0]
178+
179+
assert_equals( "pcm_s16le", dst_audioStream.getCodecName() )
180+
assert_equals( "s16", dst_audioStream.getSampleFormatName() )
181+
assert_equals( "signed 16 bits", dst_audioStream.getSampleFormatLongName() )
182+
assert_equals( 48000, dst_audioStream.getSampleRate() )
183+
assert_equals( 1, dst_audioStream.getNbChannels() )

tools/travis/python.nosetests.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ export AVTRANSCODER_TEST_IMAGE_PNG_FILE=`pwd`/avTranscoder-data/image/BigBuckBun
1818
export AVTRANSCODER_TEST_IMAGE_JPG_FILE=`pwd`/avTranscoder-data/image/BigBuckBunny/title_anouncement.thumbnail.jpg
1919

2020
# Launch tests
21-
nosetests ${TRAVIS_BUILD_DIR}/test/pyTest --with-coverage
21+
nosetests ${TRAVIS_BUILD_DIR}/test/pyTest --with-coverage > progress.txt
22+

0 commit comments

Comments
 (0)