Skip to content

Commit 07e0187

Browse files
committed
Merge pull request #233 from cchampet/feature/rewrapVideoPythonScript
Add pyrewrap python app
2 parents 1ff19b7 + 5d5f95d commit 07e0187

File tree

14 files changed

+247
-29
lines changed

14 files changed

+247
-29
lines changed

app/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ add_subdirectory(avProcessor)
77
# Python apps
88
add_subdirectory(pyProcessor)
99
add_subdirectory(pyThumbnail)
10+
add_subdirectory(pyRewrap)

app/pyRewrap/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
### python/pyRewrap
2+
3+
# Install app
4+
install(
5+
FILES "pyrewrap.py"
6+
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE
7+
DESTINATION "bin/python"
8+
)

app/pyRewrap/pyrewrap.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/usr/bin/env python
2+
3+
from pyAvTranscoder import avtranscoder as av
4+
5+
6+
# Get command line arguments
7+
args = []
8+
try:
9+
# python2.7+
10+
import argparse
11+
12+
# Create command-line interface
13+
parser = argparse.ArgumentParser(
14+
prog='pyrewrap',
15+
description='''Rewrap a video file and can move the index (moov atom) to the beginning of the file.''',
16+
)
17+
18+
# requirements
19+
parser.add_argument('inputFileName', type=str, help='It could be any video file. Support file without extension.')
20+
# options
21+
parser.add_argument("-o", "--outputFile", dest="outputFileName", type=str, default="output.mov", help="Set the output filename (thumbnail.jpg by default). Must be with jpg extension!")
22+
parser.add_argument("-c", "--format", dest="format", type=str, default="mov", help="Specify the output format.")
23+
parser.add_argument("-f", "--faststart", dest="faststart", action="store_true", default=False, help="Specify if the faststart option must be apply during rewrapping process (warning: 'mov' specific option).")
24+
# Parse command-line
25+
args = parser.parse_args()
26+
27+
except ImportError:
28+
import optparse
29+
30+
# Create command-line interface
31+
parser = optparse.OptionParser(
32+
usage='usage: %prog -o <outputfile> -c <format> [-f] -i <inputfile>',
33+
prog='pyrewrap',
34+
description='''Rewrap a video file and can move the index (moov atom) to the beginning of the file.''',
35+
)
36+
37+
# requirements
38+
parser.add_option("-i", "--inputFile", dest='inputFileName', type="string", help='It could be any video file. Support file without extension.')
39+
# options
40+
parser.add_option("-o", "--outputFile", dest="outputFileName", type="string", default="output.mov", help="Set the output filename (thumbnail.jpg by default). Must be with jpg extension!")
41+
parser.add_option("-c", "--format", dest="format", type="string", default="mov", help="Specify the output format.")
42+
parser.add_option("-f", "--faststart", dest="faststart", action="store_true", default=False, help="Specify if the faststart option must be apply during rewrapping process (warning: 'mov' specific option).")
43+
# Parse command-line
44+
args, other = parser.parse_args()
45+
46+
if args.inputFileName is None:
47+
parser.print_help()
48+
exit(1)
49+
50+
# setup avtranscoder
51+
logger = av.Logger().setLogLevel(av.AV_LOG_QUIET)
52+
av.preloadCodecsAndFormats()
53+
54+
# create input file
55+
inputFile = av.InputFile(args.inputFileName)
56+
if len(inputFile.getProperties().getVideoProperties()) == 0:
57+
print("No video stream found in file ", args.inputFileName)
58+
exit(1)
59+
60+
# create output file (need to set format profile of encoding to force output format to mp4)
61+
formatProfile = av.ProfileMap()
62+
formatProfile[ av.avProfileIdentificator ] = "mp4WrapFormatPreset"
63+
formatProfile[ av.avProfileIdentificatorHuman ] = "MP4 rewraping format preset"
64+
formatProfile[ av.avProfileType ] = av.avProfileTypeFormat
65+
formatProfile[ av.avProfileFormat ] = args.format
66+
if args.faststart:
67+
formatProfile[ "movflags" ] = "+faststart"
68+
outputFile = av.OutputFile( args.outputFileName )
69+
outputFile.setupWrapping( formatProfile )
70+
71+
# create transcoder
72+
transcoder = av.Transcoder( outputFile )
73+
74+
def addStreamsToTranscoder(transcoder, streams):
75+
for st in streams:
76+
stIndex = st.getStreamIndex()
77+
transcoder.add( args.inputFileName, stIndex )
78+
79+
addStreamsToTranscoder(transcoder, inputFile.getProperties().getVideoProperties())
80+
# addStreamsToTranscoder(transcoder, inputFile.getProperties().getAudioProperties())
81+
# addStreamsToTranscoder(transcoder, inputFile.getProperties().getDataProperties())
82+
83+
# launch process
84+
progress = av.ConsoleProgress()
85+
transcoder.process(progress)

src/AvTranscoder/decoder/AudioDecoder.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,16 @@ AudioDecoder::~AudioDecoder()
5353

5454
void AudioDecoder::setupDecoder( const ProfileLoader::Profile& profile )
5555
{
56-
LOG_DEBUG( "Set profile of audio decoder with:\n" << profile )
56+
// check the given profile
57+
const bool isValid = ProfileLoader::checkAudioProfile( profile );
58+
if( ! isValid && ! profile.empty() )
59+
{
60+
const std::string msg( "Invalid audio profile to setup decoder." );
61+
LOG_ERROR( msg )
62+
throw std::runtime_error( msg );
63+
}
64+
65+
LOG_INFO( "Setup audio decoder with:\n" << profile )
5766

5867
AudioCodec& codec = _inputStream->getAudioCodec();
5968

src/AvTranscoder/decoder/VideoDecoder.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,16 @@ VideoDecoder::~VideoDecoder()
5151

5252
void VideoDecoder::setupDecoder( const ProfileLoader::Profile& profile )
5353
{
54-
LOG_DEBUG( "Set profile of video decoder with:\n" << profile )
54+
// check the given profile
55+
const bool isValid = ProfileLoader::checkVideoProfile( profile );
56+
if( ! isValid && ! profile.empty() )
57+
{
58+
const std::string msg( "Invalid video profile to setup decoder." );
59+
LOG_ERROR( msg )
60+
throw std::runtime_error( msg );
61+
}
62+
63+
LOG_INFO( "Setup video decoder with:\n" << profile )
5564

5665
VideoCodec& codec = _inputStream->getVideoCodec();
5766

src/AvTranscoder/encoder/AudioEncoder.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ AudioEncoder::~AudioEncoder()
3737

3838
void AudioEncoder::setupAudioEncoder( const AudioFrameDesc& frameDesc, const ProfileLoader::Profile& profile )
3939
{
40-
LOG_DEBUG( "Set profile of audio encoder with:\n" << profile )
40+
LOG_INFO( "Setup audio encoder with:\n" << profile )
4141

4242
// set sampleRate, number of channels, sample format
4343
_codec.setAudioParameters( frameDesc );
@@ -48,6 +48,15 @@ void AudioEncoder::setupAudioEncoder( const AudioFrameDesc& frameDesc, const Pro
4848

4949
void AudioEncoder::setupEncoder( const ProfileLoader::Profile& profile )
5050
{
51+
// check the given profile
52+
const bool isValid = ProfileLoader::checkAudioProfile( profile );
53+
if( ! isValid && ! profile.empty() )
54+
{
55+
const std::string msg( "Invalid audio profile to setup encoder." );
56+
LOG_ERROR( msg )
57+
throw std::runtime_error( msg );
58+
}
59+
5160
// set threads before any other options
5261
if( profile.count( constants::avProfileThreads ) )
5362
_codec.getOption( constants::avProfileThreads ).setString( profile.at( constants::avProfileThreads ) );

src/AvTranscoder/encoder/VideoEncoder.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ VideoEncoder::~VideoEncoder()
3838

3939
void VideoEncoder::setupVideoEncoder( const VideoFrameDesc& frameDesc, const ProfileLoader::Profile& profile )
4040
{
41-
LOG_DEBUG( "Set profile of video encoder with:\n" << profile )
41+
LOG_INFO( "Setup video encoder with:\n" << profile )
4242

4343
// set width, height, pixel format, fps
4444
_codec.setImageParameters( frameDesc );
@@ -49,6 +49,15 @@ void VideoEncoder::setupVideoEncoder( const VideoFrameDesc& frameDesc, const Pro
4949

5050
void VideoEncoder::setupEncoder( const ProfileLoader::Profile& profile )
5151
{
52+
// check the given profile
53+
const bool isValid = ProfileLoader::checkVideoProfile( profile );
54+
if( ! isValid && ! profile.empty() )
55+
{
56+
const std::string msg( "Invalid video profile to setup encoder." );
57+
LOG_ERROR( msg )
58+
throw std::runtime_error( msg );
59+
}
60+
5261
// set threads before any other options
5362
if( profile.count( constants::avProfileThreads ) )
5463
_codec.getOption( constants::avProfileThreads ).setString( profile.at( constants::avProfileThreads ) );

src/AvTranscoder/file/FormatContext.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,11 @@ AVStream& FormatContext::getAVStream( size_t index ) const
179179
return *_avFormatContext->streams[index];
180180
}
181181

182+
void FormatContext::setFilename( const std::string& filename )
183+
{
184+
strcpy( &_avFormatContext->filename[0], filename.c_str() );
185+
}
186+
182187
void FormatContext::setOutputFormat( const std::string& filename, const std::string& shortName, const std::string& mimeType )
183188
{
184189
AVOutputFormat* oformat = av_guess_format( shortName.c_str(), filename.c_str(), mimeType.c_str() );

src/AvTranscoder/file/FormatContext.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,18 @@ class AvExport FormatContext
9494

9595
/**
9696
* Guess format from arguments.
97+
* Set the AVOutputFormat of AVFormatContext.
9798
* @param filename: checks if it terminates with the extensions of the registered formats
9899
* @param shortName: checks if it matches with the names of the registered formats
99100
* @param mimeType: checks if it matches with the MIME type of the registered formats
100101
*/
101102
void setOutputFormat( const std::string& filename, const std::string& shortName = "", const std::string& mimeType = "" );
102103

104+
/**
105+
* Set filename of AVFormatContext.
106+
*/
107+
void setFilename( const std::string& filename );
108+
103109
#ifndef SWIG
104110
AVFormatContext& getAVFormatContext() const { return *_avFormatContext; }
105111
AVOutputFormat& getAVOutputFormat() const { return *_avFormatContext->oformat; }

src/AvTranscoder/file/InputFile.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,17 @@ double InputFile::getFps()
162162

163163
void InputFile::setupUnwrapping( const ProfileLoader::Profile& profile )
164164
{
165-
LOG_DEBUG( "Set profile of input file with:\n" << profile )
165+
// check the given profile
166+
const bool isValid = ProfileLoader::checkFormatProfile( profile );
167+
if( ! isValid )
168+
{
169+
std::string msg( "Invalid format profile to setup unwrapping." );
170+
LOG_ERROR( msg )
171+
throw std::runtime_error( msg );
172+
}
173+
174+
// set profile
175+
LOG_INFO( "Setup unwrapping with:\n" << profile )
166176

167177
for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it )
168178
{

src/AvTranscoder/file/OutputFile.cpp

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ OutputFile::OutputFile( const std::string& filename )
1111
: _formatContext( AV_OPT_FLAG_ENCODING_PARAM )
1212
, _outputStreams()
1313
, _frameCount()
14-
, _filename( filename )
1514
, _previousProcessedStreamDuration( 0.0 )
15+
, _profile()
1616
{
17-
_formatContext.setOutputFormat( _filename );
17+
_formatContext.setFilename( filename );
18+
_formatContext.setOutputFormat( filename );
1819
}
1920

2021
OutputFile::~OutputFile()
@@ -85,11 +86,16 @@ IOutputStream& OutputFile::getStream( const size_t streamId )
8586
return *_outputStreams.at( streamId );
8687
}
8788

89+
std::string OutputFile::getFilename() const
90+
{
91+
return std::string( _formatContext.getAVFormatContext().filename );
92+
}
93+
8894
std::string OutputFile::getFormatName() const
8995
{
9096
if( _formatContext.getAVOutputFormat().name == NULL )
9197
{
92-
LOG_WARN("Unknown muxer format name of '" << _filename << "'.")
98+
LOG_WARN("Unknown muxer format name of '" << getFilename() << "'.")
9399
return "";
94100
}
95101
return std::string(_formatContext.getAVOutputFormat().name);
@@ -99,7 +105,7 @@ std::string OutputFile::getFormatLongName() const
99105
{
100106
if( _formatContext.getAVOutputFormat().long_name == NULL )
101107
{
102-
LOG_WARN("Unknown muxer format long name of '" << _filename << "'.")
108+
LOG_WARN("Unknown muxer format long name of '" << getFilename() << "'.")
103109
return "";
104110
}
105111
return std::string(_formatContext.getAVOutputFormat().long_name);
@@ -109,7 +115,7 @@ std::string OutputFile::getFormatMimeType() const
109115
{
110116
if( _formatContext.getAVOutputFormat().mime_type == NULL )
111117
{
112-
LOG_WARN("Unknown muxer format mime type of '" << _filename << "'.")
118+
LOG_WARN("Unknown muxer format mime type of '" << getFilename() << "'.")
113119
return "";
114120
}
115121
return std::string(_formatContext.getAVOutputFormat().mime_type);
@@ -119,9 +125,12 @@ bool OutputFile::beginWrap( )
119125
{
120126
LOG_DEBUG( "Begin wrap of OutputFile" )
121127

122-
_formatContext.openRessource( _filename, AVIO_FLAG_WRITE );
128+
_formatContext.openRessource( getFilename(), AVIO_FLAG_WRITE );
123129
_formatContext.writeHeader();
124130

131+
// set specific wrapping options
132+
setupRemainingWrappingOptions();
133+
125134
_frameCount.clear();
126135
_frameCount.resize( _outputStreams.size(), 0 );
127136

@@ -183,19 +192,57 @@ void OutputFile::addMetadata( const std::string& key, const std::string& value )
183192

184193
void OutputFile::setupWrapping( const ProfileLoader::Profile& profile )
185194
{
186-
LOG_DEBUG( "Set profile of output file with:\n" << profile )
195+
// check the given profile
196+
const bool isValid = ProfileLoader::checkFormatProfile( profile );
197+
if( ! isValid )
198+
{
199+
const std::string msg( "Invalid format profile to setup wrapping." );
200+
LOG_ERROR( msg )
201+
throw std::runtime_error( msg );
202+
}
203+
204+
LOG_INFO( "Setup wrapping with:\n" << profile )
187205

188206
// check if output format indicated is valid with the filename extension
189-
if( ! matchFormat( profile.find( constants::avProfileFormat )->second, _filename ) )
207+
if( ! matchFormat( profile.find( constants::avProfileFormat )->second, getFilename() ) )
190208
{
191209
throw std::runtime_error( "Invalid format according to the file extension." );
192210
}
193-
194211
// set output format
195-
_formatContext.setOutputFormat( _filename, profile.find( constants::avProfileFormat )->second );
212+
_formatContext.setOutputFormat( getFilename(), profile.find( constants::avProfileFormat )->second );
196213

214+
// set common wrapping options
215+
setupWrappingOptions( profile );
216+
}
217+
218+
void OutputFile::setupWrappingOptions( const ProfileLoader::Profile& profile )
219+
{
197220
// set format options
198221
for( ProfileLoader::Profile::const_iterator it = profile.begin(); it != profile.end(); ++it )
222+
{
223+
if( (*it).first == constants::avProfileIdentificator ||
224+
(*it).first == constants::avProfileIdentificatorHuman ||
225+
(*it).first == constants::avProfileType ||
226+
(*it).first == constants::avProfileFormat )
227+
continue;
228+
229+
try
230+
{
231+
Option& formatOption = _formatContext.getOption( (*it).first );
232+
formatOption.setString( (*it).second );
233+
}
234+
catch( std::exception& e )
235+
{
236+
LOG_INFO( "OutputFile - option " << (*it).first << " will be saved to be called when beginWrap" )
237+
_profile[ (*it).first ] = (*it).second;
238+
}
239+
}
240+
}
241+
242+
void OutputFile::setupRemainingWrappingOptions()
243+
{
244+
// set format options
245+
for( ProfileLoader::Profile::const_iterator it = _profile.begin(); it != _profile.end(); ++it )
199246
{
200247
if( (*it).first == constants::avProfileIdentificator ||
201248
(*it).first == constants::avProfileIdentificatorHuman ||

0 commit comments

Comments
 (0)