Skip to content

Commit d09cc28

Browse files
authored
Merge pull request #269 from cchampet/dev_transcoderRewrapToMultiChannels
Transcoder: can extract several channels from an input stream, and encode them to one output stream
2 parents c6719a6 + a9959cc commit d09cc28

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+533
-640
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@ CMakeFiles
2121
Makefile
2222
cmake_install.cmake
2323
install_manifest.txt
24+
25+
# Python
26+
*.pyc
27+

app/avProcessor/avProcessor.cpp

Lines changed: 9 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,6 @@
99
#include <sstream>
1010
#include <cstdlib>
1111

12-
static const size_t dummyWidth = 1920;
13-
static const size_t dummyHeight = 1080;
14-
static const std::string dummyPixelFormat = "yuv420p";
15-
static const std::string dummyVideoCodec = "mpeg2video";
16-
17-
static const size_t dummySampleRate = 48000;
18-
static const size_t dummyChannels = 1;
19-
static const std::string dummySampleFormat = "s16";
20-
static const std::string dummyAudioCodec = "pcm_s16le";
21-
22-
static bool useVideoGenerator = false;
23-
2412
void parseConfigFile(const std::string& configFilename, avtranscoder::Transcoder& transcoder)
2513
{
2614
std::ifstream configFile(configFilename.c_str(), std::ifstream::in);
@@ -41,37 +29,23 @@ void parseConfigFile(const std::string& configFilename, avtranscoder::Transcoder
4129
std::stringstream ss(streamId);
4230
size_t streamIndex = 0;
4331
char separator;
44-
int subStreamIndex = -1;
32+
std::vector<size_t> channelIndexArray;
4533
ss >> streamIndex;
4634
ss >> separator;
4735
if(separator == '.')
36+
{
37+
int subStreamIndex = -1;
4838
ss >> subStreamIndex;
39+
channelIndexArray.push_back(subStreamIndex);
40+
}
4941

50-
// dummy stream, need a ICodec (audio or video)
42+
// generated stream
5143
if(!filename.length())
52-
{
53-
if(useVideoGenerator)
54-
{
55-
// video
56-
avtranscoder::VideoCodec inputCodec(avtranscoder::eCodecTypeEncoder, dummyVideoCodec);
57-
avtranscoder::VideoFrameDesc imageDesc(dummyWidth, dummyHeight, dummyPixelFormat);
58-
inputCodec.setImageParameters(imageDesc);
59-
60-
transcoder.add(filename, streamIndex, subStreamIndex, transcodeProfile, inputCodec);
61-
}
62-
else
63-
{
64-
// audio
65-
avtranscoder::AudioCodec inputCodec(avtranscoder::eCodecTypeEncoder, dummyAudioCodec);
66-
avtranscoder::AudioFrameDesc audioDesc(dummySampleRate, dummyChannels, dummySampleFormat);
67-
inputCodec.setAudioParameters(audioDesc);
68-
69-
transcoder.add(filename, streamIndex, subStreamIndex, transcodeProfile, inputCodec);
70-
}
71-
}
44+
transcoder.addGenerateStream(transcodeProfile);
7245
else
7346
{
74-
transcoder.add(filename, streamIndex, subStreamIndex, transcodeProfile);
47+
avtranscoder::InputStreamDesc inputDesc(filename, streamIndex, channelIndexArray);
48+
transcoder.addStream(inputDesc, transcodeProfile);
7549
}
7650
}
7751
}
@@ -93,8 +67,6 @@ int main(int argc, char** argv)
9367
help += "\tNo subStreamId: will process of channels of the stream\n";
9468
help += "\tNo profileName: will rewrap the stream\n";
9569
help += "Command line options\n";
96-
help += "\t--generate-black: stream which not referred to an input, will generate an output video stream with black "
97-
"images (by default generate audio stream with silence)\n";
9870
help += "\t--verbose: set log level to AV_LOG_DEBUG\n";
9971
help += "\t--logFile: put log in 'avtranscoder.log' file\n";
10072
help += "\t--help: display this help\n";
@@ -116,10 +88,6 @@ int main(int argc, char** argv)
11688
std::cout << help << std::endl;
11789
return 0;
11890
}
119-
else if(arguments.at(argument) == "--generate-black")
120-
{
121-
useVideoGenerator = true;
122-
}
12391
else if(arguments.at(argument) == "--verbose")
12492
{
12593
avtranscoder::Logger::setLogLevel(AV_LOG_DEBUG);

app/pyProcessor/pyprocessor.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ def parseConfigFile( inputConfigFile, transcoder ):
1919
streamIndex = int(streamIndexes)
2020
subStreamIndex = -1
2121

22-
transcoder.add( filename, streamIndex, subStreamIndex, profileName )
22+
inputDesc = av.InputStreamDesc(filename, streamIndex, subStreamIndex)
23+
transcoder.addStream(inputDesc, profileName)
2324

2425

2526
# Create command-line interface
@@ -35,7 +36,7 @@ def parseConfigFile( inputConfigFile, transcoder ):
3536
args = parser.parse_args()
3637

3738
# setup avtranscoder
38-
logger = av.Logger().setLogLevel(av.AV_LOG_QUIET)
39+
av.Logger().setLogLevel(av.AV_LOG_QUIET)
3940
av.preloadCodecsAndFormats()
4041

4142
# create Transcoder

app/pyRewrap/pyrewrap.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@
7070

7171
# create transcoder
7272
transcoder = av.Transcoder( outputFile )
73-
transcoder.add( args.inputFileName )
73+
for streamIndex in range(0, inputFile.getProperties().getNbStreams()):
74+
transcoder.addStream(av.InputStreamDesc(args.inputFileName, streamIndex))
7475

7576
# launch process
7677
progress = av.ConsoleProgress()

app/pyThumbnail/pythumbnail.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797

9898
# create transcoder
9999
transcoder = av.Transcoder( outputFile )
100-
transcoder.add( outputStream )
100+
transcoder.addStream( outputStream )
101101

102102
# launch process
103103
outputFile.beginWrap()

src/AvTranscoder/data/decoded/AudioFrame.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ AudioFrame::AudioFrame(const Frame& otherFrame)
5050
{
5151
}
5252

53+
std::string AudioFrame::getChannelLayoutDesc() const
54+
{
55+
char buf[512];
56+
av_get_channel_layout_string(buf, sizeof(buf), getNbChannels(), getChannelLayout());
57+
return std::string(buf);
58+
}
59+
5360
size_t AudioFrame::getSize() const
5461
{
5562
if(getSampleFormat() == AV_SAMPLE_FMT_NONE)

src/AvTranscoder/data/decoded/AudioFrame.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class AvExport AudioFrame : public Frame
4545
size_t getSampleRate() const { return av_frame_get_sample_rate(_frame); }
4646
size_t getNbChannels() const { return av_frame_get_channels(_frame); }
4747
size_t getChannelLayout() const { return av_frame_get_channel_layout(_frame); }
48+
std::string getChannelLayoutDesc() const; ///< Get a description of a channel layout (example: '5.1').
4849
AVSampleFormat getSampleFormat() const { return static_cast<AVSampleFormat>(_frame->format); }
4950
size_t getNbSamplesPerChannel() const { return _frame->nb_samples; }
5051
AudioFrameDesc desc() const { return AudioFrameDesc(getSampleRate(), getNbChannels(), getSampleFormat()); }

src/AvTranscoder/decoder/AudioDecoder.cpp

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -116,57 +116,76 @@ bool AudioDecoder::decodeNextFrame(Frame& frameBuffer)
116116
return decodeNextFrame;
117117
}
118118

119-
bool AudioDecoder::decodeNextFrame(Frame& frameBuffer, const size_t channelIndex)
119+
bool AudioDecoder::decodeNextFrame(Frame& frameBuffer, const std::vector<size_t> channelIndexArray)
120120
{
121-
AudioFrame& audioBuffer = static_cast<AudioFrame&>(frameBuffer);
122-
123-
// decode all data of the next frame
124-
AudioFrame allDataOfNextFrame(audioBuffer);
125-
if(!decodeNextFrame(allDataOfNextFrame))
126-
return false;
127-
128121
AVCodecContext& avCodecContext = _inputStream->getAudioCodec().getAVCodecContext();
129122
const size_t srcNbChannels = avCodecContext.channels;
130123
const size_t bytePerSample = av_get_bytes_per_sample((AVSampleFormat)frameBuffer.getAVFrame().format);
131124

125+
// if all channels of the stream are extracted
126+
if(srcNbChannels == channelIndexArray.size())
127+
return decodeNextFrame(frameBuffer);
128+
129+
// else decode all data in an intermediate buffer
130+
AudioFrame allDataOfNextFrame(frameBuffer);
131+
if(!decodeNextFrame(allDataOfNextFrame))
132+
return false;
133+
132134
const int dstNbChannels = 1;
133135
const int noAlignment = 0;
134136
const size_t decodedSize = av_samples_get_buffer_size(NULL, dstNbChannels, frameBuffer.getAVFrame().nb_samples,
135137
avCodecContext.sample_fmt, noAlignment);
136138
if(decodedSize == 0)
137139
return false;
138140

139-
// check if the expected channel exists
140-
if(channelIndex > srcNbChannels - 1)
141+
// check if each expected channel exists
142+
for(std::vector<size_t>::const_iterator channelIndex = channelIndexArray.begin();
143+
channelIndex != channelIndexArray.end(); ++channelIndex)
141144
{
142-
std::stringstream msg;
143-
msg << "The channel at index ";
144-
msg << channelIndex;
145-
msg << " doesn't exist (srcNbChannels = ";
146-
msg << srcNbChannels;
147-
msg << ").";
148-
throw std::runtime_error(msg.str());
145+
if((*channelIndex) > srcNbChannels - 1)
146+
{
147+
std::stringstream msg;
148+
msg << "The channel at index ";
149+
msg << (*channelIndex);
150+
msg << " doesn't exist (srcNbChannels = ";
151+
msg << srcNbChannels;
152+
msg << ").";
153+
throw std::runtime_error(msg.str());
154+
}
149155
}
150156

151157
// copy frame properties of decoded frame
158+
AudioFrame& audioBuffer = static_cast<AudioFrame&>(frameBuffer);
152159
audioBuffer.copyProperties(allDataOfNextFrame);
153-
av_frame_set_channels(&audioBuffer.getAVFrame(), 1);
154-
av_frame_set_channel_layout(&audioBuffer.getAVFrame(), AV_CH_LAYOUT_MONO);
160+
av_frame_set_channels(&audioBuffer.getAVFrame(), channelIndexArray.size());
161+
av_frame_set_channel_layout(&audioBuffer.getAVFrame(), av_get_default_channel_layout(channelIndexArray.size()));
155162
audioBuffer.setNbSamplesPerChannel(allDataOfNextFrame.getNbSamplesPerChannel());
156163

157164
// @todo manage cases with data of frame not only on data[0] (use _frame.linesize)
158165
unsigned char* src = allDataOfNextFrame.getData()[0];
159166
unsigned char* dst = audioBuffer.getData()[0];
160167

161-
// offset
162-
src += channelIndex * bytePerSample;
163-
164-
// extract one channel
165-
for(int sample = 0; sample < allDataOfNextFrame.getAVFrame().nb_samples; ++sample)
168+
// extract one or more channels
169+
for(size_t sample = 0; sample < allDataOfNextFrame.getNbSamplesPerChannel(); ++sample)
166170
{
167-
memcpy(dst, src, bytePerSample);
168-
dst += bytePerSample;
169-
src += bytePerSample * srcNbChannels;
171+
// offset in source buffer
172+
src += channelIndexArray.at(0) * bytePerSample;
173+
174+
for(size_t i = 0; i < channelIndexArray.size(); ++i)
175+
{
176+
memcpy(dst, src, bytePerSample);
177+
dst += bytePerSample;
178+
179+
// shift to the corresponding sample in the next channel of the current layout
180+
if(i < channelIndexArray.size() - 1)
181+
src += (channelIndexArray.at(i + 1) - channelIndexArray.at(i)) * bytePerSample;
182+
// else shift to the next layout
183+
else
184+
{
185+
src += (srcNbChannels - channelIndexArray.at(i)) * bytePerSample;
186+
break;
187+
}
188+
}
170189
}
171190

172191
return true;

src/AvTranscoder/decoder/AudioDecoder.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class AvExport AudioDecoder : public IDecoder
1717
void setupDecoder(const ProfileLoader::Profile& profile = ProfileLoader::Profile());
1818

1919
bool decodeNextFrame(Frame& frameBuffer);
20-
bool decodeNextFrame(Frame& frameBuffer, const size_t channelIndex);
20+
bool decodeNextFrame(Frame& frameBuffer, const std::vector<size_t> channelIndexArray);
2121

2222
void flushDecoder();
2323

src/AvTranscoder/decoder/AudioGenerator.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ bool AudioGenerator::decodeNextFrame(Frame& frameBuffer)
3434
if(frameBuffer.getAVFrame().channel_layout == 0)
3535
{
3636
const size_t channelLayout = av_get_default_channel_layout(frameBuffer.getAVFrame().channels);
37-
LOG_WARN("Channel layout en the audio frame is not set. Set it to '" << channelLayout << "' to be able to copy silence data.")
37+
LOG_WARN("Channel layout en the audio frame is not set. Set it to '" << channelLayout
38+
<< "' to be able to copy silence data.")
3839
av_frame_set_channel_layout(&frameBuffer.getAVFrame(), channelLayout);
3940
}
4041

@@ -71,7 +72,7 @@ bool AudioGenerator::decodeNextFrame(Frame& frameBuffer)
7172
return true;
7273
}
7374

74-
bool AudioGenerator::decodeNextFrame(Frame& frameBuffer, const size_t subStreamIndex)
75+
bool AudioGenerator::decodeNextFrame(Frame& frameBuffer, const std::vector<size_t> channelIndexArray)
7576
{
7677
return decodeNextFrame(frameBuffer);
7778
}

src/AvTranscoder/decoder/AudioGenerator.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ class AvExport AudioGenerator : public IDecoder
1919
~AudioGenerator();
2020

2121
bool decodeNextFrame(Frame& frameBuffer);
22-
bool decodeNextFrame(Frame& frameBuffer, const size_t subStreamIndex);
22+
bool decodeNextFrame(Frame& frameBuffer, const std::vector<size_t> channelIndexArray);
2323

2424
void setNextFrame(Frame& inputFrame) { _inputFrame = &inputFrame; }
2525

2626
private:
27-
Frame* _inputFrame; ///< Has link (no ownership)
28-
AudioFrame* _silent; ///< The generated silent (has ownership)
27+
Frame* _inputFrame; ///< Has link (no ownership)
28+
AudioFrame* _silent; ///< The generated silent (has ownership)
2929
const AudioFrameDesc _frameDesc; ///< The description of the silence (sampleRate, channels...)
3030
};
3131
}

src/AvTranscoder/decoder/IDecoder.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ class AvExport IDecoder
3333
/**
3434
* @brief Decode substream of next frame
3535
* @param frameBuffer: the frame decoded
36-
* @param channelIndex: index of channel to extract
36+
* @param channelIndexArray: list of channels to extract
3737
* @return status of decoding
3838
*/
39-
virtual bool decodeNextFrame(Frame& frameBuffer, const size_t channelIndex) = 0;
39+
virtual bool decodeNextFrame(Frame& frameBuffer, const std::vector<size_t> channelIndexArray) = 0;
4040

4141
/**
4242
* @brief Set the next frame of the input stream (which bypass the work of decoding)

src/AvTranscoder/decoder/VideoDecoder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ bool VideoDecoder::decodeNextFrame(Frame& frameBuffer)
114114
return decodeNextFrame;
115115
}
116116

117-
bool VideoDecoder::decodeNextFrame(Frame& frameBuffer, const size_t subStreamIndex)
117+
bool VideoDecoder::decodeNextFrame(Frame& frameBuffer, const std::vector<size_t> channelIndexArray)
118118
{
119119
return false;
120120
}

src/AvTranscoder/decoder/VideoDecoder.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class AvExport VideoDecoder : public IDecoder
1717
void setupDecoder(const ProfileLoader::Profile& profile = ProfileLoader::Profile());
1818

1919
bool decodeNextFrame(Frame& frameBuffer);
20-
bool decodeNextFrame(Frame& frameBuffer, const size_t subStreamIndex);
20+
bool decodeNextFrame(Frame& frameBuffer, const std::vector<size_t> channelIndexArray);
2121

2222
void flushDecoder();
2323

src/AvTranscoder/decoder/VideoGenerator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ bool VideoGenerator::decodeNextFrame(Frame& frameBuffer)
7272
return true;
7373
}
7474

75-
bool VideoGenerator::decodeNextFrame(Frame& frameBuffer, const size_t channelIndex)
75+
bool VideoGenerator::decodeNextFrame(Frame& frameBuffer, const std::vector<size_t> channelIndexArray)
7676
{
7777
return false;
7878
}

src/AvTranscoder/decoder/VideoGenerator.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ class AvExport VideoGenerator : public IDecoder
1919
~VideoGenerator();
2020

2121
bool decodeNextFrame(Frame& frameBuffer);
22-
bool decodeNextFrame(Frame& frameBuffer, const size_t channelIndex);
22+
bool decodeNextFrame(Frame& frameBuffer, const std::vector<size_t> channelIndexArray);
2323

2424
void setNextFrame(Frame& inputFrame) { _inputFrame = &inputFrame; }
2525

2626
private:
27-
Frame* _inputFrame; ///< A frame given from outside (has link, no ownership)
28-
VideoFrame* _blackImage; ///< The generated black image (has ownership)
27+
Frame* _inputFrame; ///< A frame given from outside (has link, no ownership)
28+
VideoFrame* _blackImage; ///< The generated black image (has ownership)
2929
const VideoFrameDesc _frameDesc; ///< The description of the black image (width, height...)
3030
};
3131
}

src/AvTranscoder/encoder/AudioEncoder.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,4 @@ bool AudioEncoder::encode(const AVFrame* decodedData, AVPacket& encodedData)
139139
return true;
140140
#endif
141141
}
142-
143142
}

src/AvTranscoder/encoder/VideoEncoder.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,5 +152,4 @@ bool VideoEncoder::encode(const AVFrame* decodedData, AVPacket& encodedData)
152152
return true;
153153
#endif
154154
}
155-
156155
}

src/AvTranscoder/file/FormatContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ AVStream& FormatContext::addAVStream(const AVCodec& avCodec)
144144

145145
bool FormatContext::seek(const uint64_t position, const int flag)
146146
{
147-
LOG_INFO("Seek in '" << _avFormatContext->filename << "' at " << position << " with flag '"<< flag << "'")
147+
LOG_INFO("Seek in '" << _avFormatContext->filename << "' at " << position << " with flag '" << flag << "'")
148148
const int err = av_seek_frame(_avFormatContext, -1, position, flag);
149149
if(err < 0)
150150
{

src/AvTranscoder/file/FormatContext.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ class AvExport FormatContext
7878
* @param position: can be in AV_TIME_BASE units, in frames... depending on the flag value
7979
* @param flag: seeking mode (AVSEEK_FLAG_xxx)
8080
* @return seek status
81-
* @warn seeking on a raw bitstreams (without any container) could produce an error (because of a lack of timing information)
81+
* @warn seeking on a raw bitstreams (without any container) could produce an error (because of a lack of timing
82+
* information)
8283
* @see flushDecoder
8384
*/
8485
bool seek(const uint64_t position, const int flag);

0 commit comments

Comments
 (0)