1
1
#include " OutputFile.hpp"
2
2
3
- #include < AvTranscoder/option/Context.hpp>
4
-
5
- extern " C" {
6
- #include < libavcodec/avcodec.h>
7
- #include < libavformat/avformat.h>
8
- }
9
-
10
3
#include < iostream>
11
4
#include < stdexcept>
12
- #include < cassert>
13
5
14
6
namespace avtranscoder
15
7
{
16
8
17
9
OutputFile::OutputFile ( const std::string& filename )
18
- : _formatContext ( NULL )
19
- , _outputFormat ( NULL )
20
- , _filename ( filename )
10
+ : _formatContext( AV_OPT_FLAG_ENCODING_PARAM )
11
+ , _outputStreams()
12
+ , _frameCount()
13
+ , _filename( filename )
21
14
, _previousProcessedStreamDuration( 0.0 )
22
- , _verbose ( false )
23
- {
24
- if ( ( _formatContext = avformat_alloc_context () ) == NULL )
25
- {
26
- throw std::runtime_error ( " unable to create format context" );
27
- }
28
- }
15
+ , _verbose( false )
16
+ {}
29
17
30
18
bool OutputFile::setup ()
31
19
{
32
- av_register_all ();
33
- if ( ! _outputFormat )
34
- _outputFormat = av_guess_format ( NULL , _filename.c_str (), NULL );
35
-
36
- if ( ! _outputFormat )
37
- {
38
- throw std::ios_base::failure ( " unable to find format" );
39
- }
40
-
41
- _formatContext->oformat = _outputFormat;
42
-
43
- if ( !( _outputFormat->flags & AVFMT_NOFILE ) )
44
- {
45
- if ( avio_open2 ( &_formatContext->pb , _filename.c_str (), AVIO_FLAG_WRITE, NULL , NULL ) < 0 )
46
- {
47
- avformat_close_input ( &_formatContext );
48
- _formatContext = NULL ;
49
- throw std::ios_base::failure ( " error when opening output format" );
50
- }
51
- }
52
-
53
- return _formatContext != NULL ;
20
+ _formatContext.setOutputFormat ( _filename );
21
+ _formatContext.openRessource ( _filename, AVIO_FLAG_WRITE );
22
+ return true ;
54
23
}
55
24
56
25
IOutputStream& OutputFile::addVideoStream ( const VideoCodec& videoDesc )
57
26
{
58
- assert ( _formatContext != NULL );
59
-
60
- AVStream* stream = avformat_new_stream ( _formatContext, videoDesc.getAVCodec () );
61
- if ( stream == NULL )
62
- {
63
- throw std::runtime_error ( " unable to add new video stream" );
64
- }
27
+ AVStream& stream = _formatContext.addAVStream ( *videoDesc.getAVCodec () );
65
28
66
- stream-> codec ->width = videoDesc.getAVCodecContext ()->width ;
67
- stream-> codec ->height = videoDesc.getAVCodecContext ()->height ;
68
- stream-> codec ->bit_rate = videoDesc.getAVCodecContext ()->bit_rate ;
69
- stream-> codec ->pix_fmt = videoDesc.getAVCodecContext ()->pix_fmt ;
70
- stream-> codec ->profile = videoDesc.getAVCodecContext ()->profile ;
71
- stream-> codec ->level = videoDesc.getAVCodecContext ()->level ;
29
+ stream. codec ->width = videoDesc.getAVCodecContext ()->width ;
30
+ stream. codec ->height = videoDesc.getAVCodecContext ()->height ;
31
+ stream. codec ->bit_rate = videoDesc.getAVCodecContext ()->bit_rate ;
32
+ stream. codec ->pix_fmt = videoDesc.getAVCodecContext ()->pix_fmt ;
33
+ stream. codec ->profile = videoDesc.getAVCodecContext ()->profile ;
34
+ stream. codec ->level = videoDesc.getAVCodecContext ()->level ;
72
35
73
36
// need to set the time_base on the AVCodecContext and the AVStream
74
37
// compensating the frame rate with the ticks_per_frame and keeping
75
38
// a coherent reading speed.
76
39
av_reduce (
77
- &stream-> codec ->time_base .num ,
78
- &stream-> codec ->time_base .den ,
40
+ &stream. codec ->time_base .num ,
41
+ &stream. codec ->time_base .den ,
79
42
videoDesc.getAVCodecContext ()->time_base .num * videoDesc.getAVCodecContext ()->ticks_per_frame ,
80
43
videoDesc.getAVCodecContext ()->time_base .den ,
81
44
INT_MAX );
82
45
83
- stream-> time_base = stream-> codec ->time_base ;
46
+ stream. time_base = stream. codec ->time_base ;
84
47
85
- AvOutputStream* avOutputStream = new AvOutputStream ( *this , _formatContext-> nb_streams - 1 );
48
+ AvOutputStream* avOutputStream = new AvOutputStream ( *this , _formatContext. getNbStreams () - 1 );
86
49
_outputStreams.push_back ( avOutputStream );
87
50
88
51
return *_outputStreams.back ();
89
52
}
90
53
91
54
IOutputStream& OutputFile::addAudioStream ( const AudioCodec& audioDesc )
92
55
{
93
- assert ( _formatContext != NULL );
56
+ AVStream& stream = _formatContext. addAVStream ( *audioDesc. getAVCodec () );
94
57
95
- AVStream* stream = avformat_new_stream ( _formatContext, audioDesc.getAVCodec () );
96
- if ( stream == NULL )
97
- {
98
- throw std::runtime_error ( " unable to add new audio stream" );
99
- }
58
+ stream.codec ->sample_rate = audioDesc.getAVCodecContext ()->sample_rate ;
59
+ stream.codec ->channels = audioDesc.getAVCodecContext ()->channels ;
60
+ stream.codec ->sample_fmt = audioDesc.getAVCodecContext ()->sample_fmt ;
100
61
101
- stream->codec ->sample_rate = audioDesc.getAVCodecContext ()->sample_rate ;
102
- stream->codec ->channels = audioDesc.getAVCodecContext ()->channels ;
103
- stream->codec ->sample_fmt = audioDesc.getAVCodecContext ()->sample_fmt ;
104
-
105
- AvOutputStream* avOutputStream = new AvOutputStream ( *this , _formatContext->nb_streams - 1 );
62
+ AvOutputStream* avOutputStream = new AvOutputStream ( *this , _formatContext.getNbStreams () - 1 );
106
63
_outputStreams.push_back ( avOutputStream );
107
64
108
65
return *_outputStreams.back ();
109
66
}
110
67
111
68
IOutputStream& OutputFile::addDataStream ( const DataCodec& dataDesc )
112
69
{
113
- assert ( _formatContext != NULL );
114
-
115
- AVStream* stream = avformat_new_stream ( _formatContext, dataDesc.getAVCodec () );
116
- if ( stream == NULL )
117
- {
118
- throw std::runtime_error ( " unable to add new data stream" );
119
- }
70
+ _formatContext.addAVStream ( *dataDesc.getAVCodec () );
120
71
121
- AvOutputStream* avOutputStream = new AvOutputStream ( *this , _formatContext-> nb_streams - 1 );
72
+ AvOutputStream* avOutputStream = new AvOutputStream ( *this , _formatContext. getNbStreams () - 1 );
122
73
_outputStreams.push_back ( avOutputStream );
123
74
124
75
return *_outputStreams.back ();
@@ -133,15 +84,7 @@ IOutputStream& OutputFile::getStream( const size_t streamId )
133
84
134
85
bool OutputFile::beginWrap ( )
135
86
{
136
- int ret = avformat_write_header ( _formatContext, NULL );
137
- if ( ret != 0 )
138
- {
139
- char err[AV_ERROR_MAX_STRING_SIZE];
140
- av_strerror ( ret, err, sizeof (err) );
141
- std::string msg = " could not write header: " ;
142
- msg += err;
143
- throw std::runtime_error ( msg );
144
- }
87
+ _formatContext.writeHeader ();
145
88
_frameCount.clear ();
146
89
_frameCount.resize ( _outputStreams.size (), 0 );
147
90
return true ;
@@ -165,26 +108,13 @@ IOutputStream::EWrappingStatus OutputFile::wrap( const CodedData& data, const si
165
108
// packet.dts = _frameCount.at( streamId );
166
109
// packet.pts = ;
167
110
168
- // int ret = av_write_frame( _formatContext, &packet );
169
- int ret = av_interleaved_write_frame ( _formatContext, &packet );
170
-
171
- if ( ret != 0 )
172
- {
173
- char err[AV_ERROR_MAX_STRING_SIZE];
174
- av_strerror ( ret, err, sizeof (err) );
175
- std::string msg = " error when writting packet in stream: " ;
176
- msg += err;
177
- // throw std::runtime_error( msg );
178
- std::cout << msg << std::endl;
179
- return IOutputStream::eWrappingError;
180
- }
111
+ _formatContext.writeFrame ( packet );
181
112
182
113
av_free_packet ( &packet );
183
114
184
- // get the current streams
185
- AVStream* currentStream = _formatContext->streams [ streamId ];
186
- // compute its duration
187
- double currentStreamDuration = (double )currentStream->cur_dts * currentStream->time_base .num / currentStream->time_base .den ;
115
+ // compute the duration of current stream
116
+ AVStream& currentStream = _formatContext.getAVStream ( streamId );
117
+ double currentStreamDuration = (double )currentStream.cur_dts * currentStream.time_base .num / currentStream.time_base .den ;
188
118
189
119
if ( currentStreamDuration < _previousProcessedStreamDuration )
190
120
{
@@ -200,18 +130,8 @@ IOutputStream::EWrappingStatus OutputFile::wrap( const CodedData& data, const si
200
130
201
131
bool OutputFile::endWrap ( )
202
132
{
203
- if ( av_write_trailer ( _formatContext ) != 0 )
204
- {
205
- throw std::runtime_error ( " could not write trailer" );
206
- }
207
-
208
- if ( !( _formatContext->oformat ->flags & AVFMT_NOFILE ) )
209
- {
210
- avio_close ( _formatContext->pb );
211
- }
212
- avformat_free_context ( _formatContext );
213
- // freeFormat();
214
-
133
+ _formatContext.writeTrailer ();
134
+ _formatContext.closeRessource ();
215
135
return true ;
216
136
}
217
137
@@ -225,13 +145,7 @@ void OutputFile::addMetadata( const PropertiesMap& dataMap )
225
145
226
146
void OutputFile::addMetadata ( const std::string& key, const std::string& value )
227
147
{
228
- int ret = av_dict_set ( &_formatContext->metadata , key.c_str (), value.c_str (), 0 );
229
- if ( ret < 0 )
230
- {
231
- char err[AV_ERROR_MAX_STRING_SIZE];
232
- av_strerror ( ret, err, sizeof (err) );
233
- std::cout << err << std::endl;
234
- }
148
+ _formatContext.addMetaData ( key, value );
235
149
}
236
150
237
151
void OutputFile::setProfile ( const ProfileLoader::Profile& profile )
@@ -245,9 +159,8 @@ void OutputFile::setProfile( const ProfileLoader::Profile& profile )
245
159
{
246
160
throw std::runtime_error ( " Invalid format according to the file extension." );
247
161
}
248
- _outputFormat = av_guess_format ( profile.find ( constants::avProfileFormat )->second .c_str (), _filename.c_str (), NULL );
249
162
250
- Context formatContext ( _formatContext, AV_OPT_FLAG_ENCODING_PARAM );
163
+ _formatContext. setOutputFormat ( _filename, profile. find ( constants::avProfileFormat )-> second );
251
164
252
165
for ( ProfileLoader::Profile::const_iterator it = profile.begin (); it != profile.end (); ++it )
253
166
{
@@ -259,7 +172,7 @@ void OutputFile::setProfile( const ProfileLoader::Profile& profile )
259
172
260
173
try
261
174
{
262
- Option& formatOption = formatContext .getOption ( (*it).first );
175
+ Option& formatOption = _formatContext .getOption ( (*it).first );
263
176
formatOption.setString ( (*it).second );
264
177
}
265
178
catch ( std::exception& e )
@@ -278,7 +191,7 @@ void OutputFile::setProfile( const ProfileLoader::Profile& profile )
278
191
279
192
try
280
193
{
281
- Option& formatOption = formatContext .getOption ( (*it).first );
194
+ Option& formatOption = _formatContext .getOption ( (*it).first );
282
195
formatOption.setString ( (*it).second );
283
196
}
284
197
catch ( std::exception& e )
@@ -291,10 +204,10 @@ void OutputFile::setProfile( const ProfileLoader::Profile& profile )
291
204
292
205
double OutputFile::getProgressDuration ()
293
206
{
294
- if ( _formatContext-> nb_streams == 0 )
207
+ if ( _formatContext. getNbStreams () == 0 )
295
208
throw std::runtime_error ( " at least one stream must be set to get the progress duration" );
296
- AVStream* firstOutputStream = _formatContext-> streams [ 0 ] ;
297
- return av_q2d ( firstOutputStream-> time_base ) * firstOutputStream-> cur_dts ;
209
+ AVStream& firstOutputStream = _formatContext. getAVStream ( 0 ) ;
210
+ return av_q2d ( firstOutputStream. time_base ) * firstOutputStream. cur_dts ;
298
211
}
299
212
300
213
}
0 commit comments