-
Notifications
You must be signed in to change notification settings - Fork 135
Expand file tree
/
Copy pathdemo.cpp
More file actions
295 lines (248 loc) · 8.96 KB
/
demo.cpp
File metadata and controls
295 lines (248 loc) · 8.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#include <iostream>
#include "GeneratedVideoSource.h"
#include "GeneratedAudioSource.h"
#include <ffmpegcpp.h>
using namespace ffmpegcpp;
using namespace std;
// This example demonstrates different combinations and usages for ffmpeg-cpp.
// Configure it by changing the values below.
// The list of supported codecs is not limited to the ones mentioned below,
// this is just a list we support in this demo. You can use any codec that is
// supported by ffmpeg, but you might have to write your own Codec-class wrapper
// to make it work. Look at the examples in the Codecs-dir to see how it is done.
void PlayDemo(int argc, char** argv)
{
// These are example video and audio sources used below.
const char* rawVideoFile = "samples/carphone_qcif.y4m";
int rawVideoWidth = 176; int rawVideoHeight = 162;
const char* rawAudioFile = "samples/Vivaldi_s16le_2_channels_samplerate_11025.dat";
const char* rawAudioFormat = "s16le"; int rawAudioSampleRate = 11025; int rawAudioChannels = 2;
const char* encodedVideoFile = "samples/carphone.h264";
const char* encodedAudioFile = "samples/Vivaldi_Sonata_eminor_.mp3";
const char* containerWithVideoAndAudioFile = "samples/big_buck_bunny.mp4";
const char* containerWithAudioFile = "samples/DesiJourney.wav";
// hard-code the settings here, but let them be overridden by the arguments
string inputAudioSource = "CONTAINER"; // options are RAW, ENCODED, CONTAINER, GENERATED
string inputVideoSource = "ENCODED"; // options are RAW, ENCODED, CONTAINER, GENERATED
string outputAudioCodec = "AAC"; // options are MP2, AAC, NONE
string outputVideoCodec = "H264"; // options are H264, H265, VP9, NONE (H264 and H265 only work on Nvidia hardware)
string outputContainerName = "out.mp4"; // container format is deduced from extension so use a known one
// you can use any filter string that you can use in the ffmpeg command-line here
// set the filter to NULL to disable filtering.
// See https://trac.ffmpeg.org/wiki/FilteringGuide for more info
// This example rotates the entire video and then puts a vignette on top of it.
const char* videoFilterConfig = NULL;//"transpose=cclock[middle];[middle]vignette"
// if command line is specified, we overwrite our hard-coded settings
if (argc >= 6)
{
inputAudioSource = string(argv[1]);
inputVideoSource = string(argv[2]);
outputAudioCodec = string(argv[3]);
outputVideoCodec = string(argv[4]);
videoFilterConfig = argv[5];
}
// create the different components that make this come together
try
{
/**
* CREATE THE OUTPUT CONTAINER
*/
// create the output muxer - we'll be adding encoders to it later
Muxer* muxer = new Muxer(outputContainerName.c_str());
/**
* CONFIGURE AUDIO OUTPUT
*/
// create the output encoder based on our setting above
AudioCodec* audioCodec = nullptr;
if (outputAudioCodec == "MP2")
{
printf("Encoding audio as MP2...\n");
audioCodec = new AudioCodec(AV_CODEC_ID_MP2);
}
else if (outputAudioCodec == "AAC")
{
printf("Encoding audio as AAC...\n");
audioCodec = new AudioCodec(AV_CODEC_ID_AAC);
}
else if (outputAudioCodec == "NONE")
{
// no codec specified - don't output audio!
}
// create an encoder - this encoder will receive raw data from any source (filter, file, container, memory, etc),
// encode it and send it to the muxer (the output container).
AudioEncoder* audioEncoder = nullptr;
if (audioCodec != nullptr)
{
audioEncoder = new AudioEncoder(audioCodec, muxer);
}
/**
* CONFIGURE VIDEO OUTPUT
*/
// create the output encoder based on our setting above
VideoCodec* videoCodec = nullptr;
if (outputVideoCodec == "H264")
{
printf("Encoding video as H264 on Nvidia GPU...\n");
H264NVEncCodec* h264Codec = new H264NVEncCodec();
h264Codec->SetPreset("hq");
videoCodec = h264Codec;
}
else if (outputVideoCodec == "H265")
{
printf("Encoding video as H265 on Nvidia GPU...\n");
H265NVEncCodec* h265Codec = new H265NVEncCodec();
h265Codec->SetPreset("hq");
videoCodec = h265Codec;
}
else if (outputVideoCodec == "VP9")
{
printf("Encoding video as VP9...\n");
VP9Codec* vp9Codec = new VP9Codec();
vp9Codec->SetLossless(true);
videoCodec = vp9Codec;
}
else if (outputVideoCodec == "NONE")
{
// no codec specified - don't output audio!
}
// create an encoder for the codec and tie it to the muxer
// this encoder will receive data from an input source (file, raw, filter, etc), encode it and send it to the output container (muxer)
VideoEncoder* videoEncoder = nullptr;
if (videoCodec != nullptr)
{
videoEncoder = new VideoEncoder(videoCodec, muxer);
}
/**
* CONFIGURE AUDIO INPUT
*/
// only do this when there is an output - otherwise there is no point in reading audio
InputSource* audioInputSource = nullptr;
if (audioEncoder != nullptr)
{
if (inputAudioSource == "RAW")
{
printf("Pulling audio from %s...\n", rawAudioFile);
audioInputSource = new RawAudioFileSource(rawAudioFile, rawAudioFormat, rawAudioSampleRate, rawAudioChannels, audioEncoder);
}
else if (inputAudioSource == "ENCODED")
{
printf("Pulling audio from %s...\n", encodedAudioFile);
audioInputSource = new EncodedFileSource(encodedAudioFile, AV_CODEC_ID_MP3, audioEncoder);
}
else if (inputAudioSource == "CONTAINER")
{
// if the input comes from a container, we use the demuxer class - it is just an input source like any other
printf("Pulling audio from %s...\n", containerWithAudioFile);
Demuxer* demuxer = new Demuxer(containerWithAudioFile);
demuxer->DecodeBestAudioStream(audioEncoder);
audioInputSource = demuxer;
}
else if (inputAudioSource == "GENERATED")
{
printf("Generating 440Hz audio tone...\n");
audioInputSource = new GeneratedAudioSource(audioEncoder);
}
}
/**
* CONFIGURE VIDEO FILTER IF IT IS USED
*/
VideoFrameSink* videoFrameSink = videoEncoder;
// If a video filter was specified, we inject it into the pipeline here.
// Instead of feeding the video source directly to the encoder, we feed it to
// the video filter instead, which will pass it on to the encoder.
VideoFilter* videoFilter = nullptr;
if (videoFilterConfig != NULL && videoEncoder != nullptr)
{
printf("Applying filter %s to video...\n", videoFilterConfig);
videoFilter = new VideoFilter(videoFilterConfig, videoEncoder);
videoFrameSink = videoFilter; // used to feed the source below
}
/**
* CONFIGURE VIDEO INPUT
*/
// only do this when there is video output
InputSource* videoInputSource = nullptr;
if (videoEncoder != nullptr)
{
if (inputVideoSource == "RAW")
{
printf("Pulling video from %s...\n", rawVideoFile);
videoInputSource = new RawVideoFileSource(rawVideoFile, videoFrameSink);
}
else if (inputVideoSource == "ENCODED")
{
printf("Pulling video from %s...\n", encodedVideoFile);
videoInputSource = new RawVideoFileSource(encodedVideoFile, videoFrameSink);
}
else if (inputVideoSource == "CONTAINER")
{
printf("Pulling video from %s...\n", containerWithVideoAndAudioFile);
Demuxer* demuxer = new Demuxer(containerWithVideoAndAudioFile);
demuxer->DecodeBestVideoStream(videoFrameSink);
videoInputSource = demuxer;
}
else if (inputVideoSource == "GENERATED")
{
printf("Generating checkerboard video pattern...\n");
videoInputSource = new GeneratedVideoSource(640, 480, videoFrameSink);
}
}
/**
* PROCESS THE DATA
*/
// As an awkward but necessary first step, we need to prime each input source.
// This step decodes a part of the input data and from this, generates info
// about the stream and propagates it all the way to the output container,
// which needs to write this data to its header.
if (videoInputSource != nullptr) videoInputSource->PreparePipeline();
if (audioInputSource != nullptr) audioInputSource->PreparePipeline();
// finally, we can start writing data to our pipelines. Open the floodgates
// to start reading frames from the input, decoding them, optionally filtering them,
// encoding them and writing them to the final container.
// This can be interweaved if you want to.
if (audioInputSource != nullptr)
{
while (!audioInputSource->IsDone()) audioInputSource->Step();
}
if (videoInputSource != nullptr)
{
while (!videoInputSource->IsDone()) videoInputSource->Step();
}
// close the muxer and save the file to disk
muxer->Close();
// all done
if (audioCodec != nullptr)
{
delete audioCodec;
delete audioEncoder;
}
if (videoCodec != nullptr)
{
delete videoCodec;
delete videoEncoder;
if (videoFilter != nullptr) delete videoFilter;
}
if (audioInputSource != nullptr)
{
delete audioInputSource;
}
if (videoInputSource != nullptr)
{
delete videoInputSource;
}
delete muxer;
}
catch (FFmpegException e)
{
cerr << e.what() << endl;
throw e;
}
}
int main(int argc, char **argv)
{
PlayDemo(argc, argv);
cout << "Encoding complete!" << endl;
cout << "Press any key to continue..." << endl;
getchar();
return 0;
}