Ticket #9502: ffmpeg.c

File ffmpeg.c, 11.8 KB (added by toots, 5 years ago)

Reproduction code.

Line 
1#include <libavcodec/avcodec.h>
2#include <libavdevice/avdevice.h>
3#include <libavfilter/buffersink.h>
4#include <libavfilter/buffersrc.h>
5#include <libavformat/avformat.h>
6#include <libavutil/channel_layout.h>
7#include <libavutil/opt.h>
8
9#include <sys/time.h>
10#include <unistd.h>
11
12#define OUTPUT "icecast://source:hackme@host:5008/live"
13#define RUNTIME 5
14#define WAITTIME 1
15
16typedef struct ffmpeg {
17 AVFormatContext *ifmt_ctx;
18 AVFormatContext *ofmt_ctx;
19 AVCodecContext *dec_ctx;
20 AVCodecContext *enc_ctx;
21 AVFilterContext *buffersink_ctx;
22 AVFilterContext *buffersrc_ctx;
23 AVFilterGraph *filter_graph;
24 AVPacket *packet;
25 AVFrame *frame;
26 AVFrame *filt_frame;
27 int istream_index;
28 int ostream_index;
29} ffmpeg_t;
30
31int open_input(ffmpeg_t *ffmpeg) {
32 AVCodec *dec;
33 int ret;
34 char *format_name;
35 char *in_filename;
36 AVInputFormat *format;
37 AVDictionary *opts = NULL;
38
39 format_name = "avfoundation";
40 in_filename = "none:default";
41
42 format = av_find_input_format(format_name);
43
44 if (!format) {
45 return -1;
46 }
47
48 ret = avformat_open_input(&ffmpeg->ifmt_ctx, in_filename, format, NULL);
49 if (ret < 0) {
50 return ret;
51 }
52
53 ret = avformat_find_stream_info(ffmpeg->ifmt_ctx, NULL);
54 if (ret < 0) {
55 return ret;
56 }
57
58 /* select the audio stream */
59 ret = av_find_best_stream(ffmpeg->ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec,
60 0);
61 if (ret < 0) {
62 return ret;
63 }
64 ffmpeg->istream_index = ret;
65
66 /* create decoding context */
67 ffmpeg->dec_ctx = avcodec_alloc_context3(dec);
68 if (!ffmpeg->dec_ctx)
69 return AVERROR(ENOMEM);
70
71 avcodec_parameters_to_context(
72 ffmpeg->dec_ctx,
73 ffmpeg->ifmt_ctx->streams[ffmpeg->istream_index]->codecpar);
74
75 /* init the audio decoder */
76 ret = avcodec_open2(ffmpeg->dec_ctx, dec, NULL);
77 if (ret < 0) {
78 return ret;
79 }
80
81 return 0;
82}
83
84int init_filters(ffmpeg_t *ffmpeg) {
85 int ret = 0;
86 const AVFilter *abuffersrc = avfilter_get_by_name("abuffer");
87 const AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
88 AVFilterInOut *outputs = avfilter_inout_alloc();
89 AVFilterInOut *inputs = avfilter_inout_alloc();
90 AVRational time_base =
91 ffmpeg->ifmt_ctx->streams[ffmpeg->istream_index]->time_base;
92
93 char filter_descr[1024];
94 snprintf(filter_descr, sizeof(filter_descr),
95 "aformat=sample_fmts=%s:channel_layouts=stereo,astats=metadata=true:"
96 "reset=10:measure_perchannel=RMS_level:measure_overall=none,"
97 "aresample=%d,asetnsamples=nb_out_samples=%d,asetpts=PTS-STARTPTS",
98 av_get_sample_fmt_name(ffmpeg->enc_ctx->sample_fmt),
99 ffmpeg->enc_ctx->sample_rate,
100 ffmpeg->enc_ctx->frame_size);
101
102 ffmpeg->filter_graph = avfilter_graph_alloc();
103 if (!outputs || !inputs || !ffmpeg->filter_graph) {
104 ret = AVERROR(ENOMEM);
105 goto end;
106 }
107
108 if (!ffmpeg->dec_ctx->channel_layout)
109 ffmpeg->dec_ctx->channel_layout =
110 av_get_default_channel_layout(ffmpeg->dec_ctx->channels);
111
112 char filter_args[1024];
113 snprintf(
114 filter_args, sizeof(filter_args),
115 "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=%" PRId64,
116 time_base.num, time_base.den, ffmpeg->dec_ctx->sample_rate,
117 av_get_sample_fmt_name(ffmpeg->dec_ctx->sample_fmt),
118 ffmpeg->dec_ctx->channel_layout);
119
120 ret = avfilter_graph_create_filter(&ffmpeg->buffersrc_ctx, abuffersrc, "in",
121 filter_args, NULL, ffmpeg->filter_graph);
122 if (ret < 0) {
123 goto end;
124 }
125
126 /* buffer audio sink: to terminate the filter chain. */
127 ret = avfilter_graph_create_filter(&ffmpeg->buffersink_ctx, abuffersink,
128 "out", NULL, NULL, ffmpeg->filter_graph);
129 if (ret < 0) {
130 goto end;
131 }
132
133 /*
134 * Set the endpoints for the filter graph. The filter_graph will
135 * be linked to the graph described by filter_descr.
136 */
137
138 /*
139 * The buffer source output must be connected to the input pad of
140 * the first filter described by filter_descr; since the first
141 * filter input label is not specified, it is set to "in" by
142 * default.
143 */
144 outputs->name = av_strdup("in");
145 outputs->filter_ctx = ffmpeg->buffersrc_ctx;
146 outputs->pad_idx = 0;
147 outputs->next = NULL;
148
149 /*
150 * The buffer sink input must be connected to the output pad of
151 * the last filter described by filter_descr; since the last
152 * filter output label is not specified, it is set to "out" by
153 * default.
154 */
155 inputs->name = av_strdup("out");
156 inputs->filter_ctx = ffmpeg->buffersink_ctx;
157 inputs->pad_idx = 0;
158 inputs->next = NULL;
159
160 ret = avfilter_graph_parse_ptr(ffmpeg->filter_graph, filter_descr, &inputs,
161 &outputs, NULL);
162 if (ret < 0)
163 goto end;
164
165 ret = avfilter_graph_config(ffmpeg->filter_graph, NULL);
166
167end:
168 avfilter_inout_free(&inputs);
169 avfilter_inout_free(&outputs);
170
171 return ret;
172}
173
174int encode_audio_frame(ffmpeg_t *ffmpeg) {
175 int ret;
176
177 ret = avcodec_send_frame(ffmpeg->enc_ctx, ffmpeg->filt_frame);
178 if (ret == AVERROR_EOF) {
179 return ret;
180 }
181
182 if (ret < 0) {
183 return ret;
184 }
185
186 while (ret >= 0) {
187 ret = avcodec_receive_packet(ffmpeg->enc_ctx, ffmpeg->packet);
188 if (ret == AVERROR(EAGAIN)) {
189 return 0;
190 }
191
192 if (ret == AVERROR_EOF) {
193 return AVERROR_EOF;
194 }
195
196 if (ret < 0) {
197 return ret;
198 }
199
200 ffmpeg->packet->stream_index = ffmpeg->ostream_index;
201 av_packet_rescale_ts(ffmpeg->packet, ffmpeg->enc_ctx->time_base,
202 ffmpeg->ofmt_ctx->streams[0]->time_base);
203
204 ret = av_interleaved_write_frame(ffmpeg->ofmt_ctx, ffmpeg->packet);
205 if (ret < 0) {
206 return ret;
207 }
208 }
209
210 return 0;
211}
212
213int open_output(ffmpeg_t *ffmpeg) {
214 AVStream *stream = NULL;
215 const AVCodec *output_codec = NULL;
216 AVDictionary *codec_opts = NULL;
217 AVDictionary *out_opts = NULL;
218 int error = -1;
219
220 av_dict_set(&out_opts, "content_type", "audio/mpeg", 0);
221 // av_dict_set(&out_opts, "tls", "1", 0);
222
223 /* Create a new format context for the output container format. */
224 avformat_alloc_output_context2(&ffmpeg->ofmt_ctx, NULL, "mp3", OUTPUT);
225 if (!ffmpeg->ofmt_ctx) {
226 return AVERROR(ENOMEM);
227 }
228
229 error = avio_open2(&ffmpeg->ofmt_ctx->pb, OUTPUT, AVIO_FLAG_WRITE, NULL,
230 &out_opts);
231 if (error < 0) {
232 goto cleanup;
233 }
234
235 av_dict_copy(&ffmpeg->ofmt_ctx->metadata, ffmpeg->ifmt_ctx->metadata, 0);
236
237 /* Find the encoder to be used by its name. */
238 if (!(output_codec = avcodec_find_encoder_by_name("libmp3lame"))) {
239 error = AVERROR_ENCODER_NOT_FOUND;
240 goto cleanup;
241 }
242
243 if (!(stream = avformat_new_stream(ffmpeg->ofmt_ctx, output_codec))) {
244 error = AVERROR(ENOMEM);
245 goto cleanup;
246 }
247
248 stream->id = ffmpeg->ofmt_ctx->nb_streams - 1;
249 ffmpeg->ostream_index = stream->index;
250
251 ffmpeg->enc_ctx = avcodec_alloc_context3(output_codec);
252 if (!ffmpeg->enc_ctx) {
253 error = AVERROR(ENOMEM);
254 goto cleanup;
255 }
256
257 /* Set the basic encoder parameters.
258 * The input file's sample rate is used to avoid a sample rate conversion. */
259 ffmpeg->enc_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
260 ffmpeg->enc_ctx->channels = 2;
261 ffmpeg->enc_ctx->sample_rate = 44100;
262 ;
263 ffmpeg->enc_ctx->sample_fmt = output_codec->sample_fmts[0];
264 ffmpeg->enc_ctx->time_base = (AVRational){1, ffmpeg->enc_ctx->sample_rate};
265 av_dict_set(&codec_opts, "b", "128k", 0);
266
267 /* Some container formats (like MP4) require global headers to be present.
268 * Mark the encoder so that it behaves accordingly. */
269 if ((ffmpeg->ofmt_ctx)->oformat->flags & AVFMT_GLOBALHEADER)
270 ffmpeg->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
271
272 /* Open the encoder for the audio stream to use it later. */
273 if ((error = avcodec_open2(ffmpeg->enc_ctx, output_codec, &codec_opts)) < 0) {
274 goto cleanup;
275 }
276
277 stream->time_base = ffmpeg->enc_ctx->time_base;
278
279 error = avcodec_parameters_from_context(stream->codecpar, ffmpeg->enc_ctx);
280 if (error < 0) {
281 goto cleanup;
282 }
283
284 error = avformat_write_header(ffmpeg->ofmt_ctx, NULL);
285 if (error < 0) {
286 goto cleanup;
287 }
288
289 return 0;
290
291cleanup:
292 avcodec_free_context(&ffmpeg->enc_ctx);
293 avio_closep(&(ffmpeg->ofmt_ctx)->pb);
294 avformat_free_context(ffmpeg->ofmt_ctx);
295 ffmpeg->ofmt_ctx = NULL;
296 return error;
297}
298
299int runFfmpeg() {
300 int ret;
301 ffmpeg_t ffmpeg;
302 AVDictionaryEntry *left_volume = NULL;
303 AVDictionaryEntry *right_volume = NULL;
304 double volume;
305 char *end_ptr;
306 int first;
307 double encoding_time;
308 AVRational in_time_base;
309 struct timeval start, current;
310
311 gettimeofday(&start, NULL);
312
313 memset(&ffmpeg, 0, sizeof(ffmpeg));
314
315 ffmpeg.packet = av_packet_alloc();
316 ffmpeg.frame = av_frame_alloc();
317 ffmpeg.filt_frame = av_frame_alloc();
318
319 if (!ffmpeg.packet || !ffmpeg.frame || !ffmpeg.filt_frame) {
320 return AVERROR(ENOMEM);
321 }
322
323 ret = open_input(&ffmpeg);
324 if (ret < 0)
325 goto end;
326
327 ret = open_output(&ffmpeg);
328 if (ret < 0)
329 goto end;
330
331 ret = init_filters(&ffmpeg);
332 if (ret < 0)
333 goto end;
334
335 av_dump_format(ffmpeg.ifmt_ctx, 0, "default", 0);
336 av_dump_format(ffmpeg.ofmt_ctx, 0, "icecast", 1);
337
338 in_time_base = ffmpeg.ifmt_ctx->streams[ffmpeg.istream_index]->time_base;
339 /* read all packets */
340 while (1) {
341 gettimeofday(&current, NULL);
342 if (RUNTIME < current.tv_sec - start.tv_sec) {
343 printf("Reached max time!\n");
344 ret = 0;
345 goto end;
346 }
347
348 do {
349 ret = av_read_frame(ffmpeg.ifmt_ctx, ffmpeg.packet);
350 } while (ret > 0 || ret == AVERROR(EAGAIN));
351
352 if (ret < 0)
353 break;
354
355 if (ffmpeg.packet->stream_index == ffmpeg.istream_index) {
356 ret = avcodec_send_packet(ffmpeg.dec_ctx, ffmpeg.packet);
357 av_packet_unref(ffmpeg.packet);
358
359 if (ret < 0)
360 goto end;
361
362 while (ret >= 0) {
363 ret = avcodec_receive_frame(ffmpeg.dec_ctx, ffmpeg.frame);
364 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
365 break;
366 if (ret < 0)
367 goto end;
368
369 /* push the audio data from decoded frame into the filtergraph */
370 ret = av_buffersrc_add_frame_flags(ffmpeg.buffersrc_ctx, ffmpeg.frame,
371 AV_BUFFERSRC_FLAG_KEEP_REF);
372 av_frame_unref(ffmpeg.frame);
373
374 if (ret < 0)
375 goto end;
376
377 /* pull filtered audio from the filtergraph */
378 while (1) {
379 ret =
380 av_buffersink_get_frame(ffmpeg.buffersink_ctx, ffmpeg.filt_frame);
381 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
382 break;
383 if (ret < 0)
384 goto end;
385
386 left_volume = av_dict_get(ffmpeg.filt_frame->metadata,
387 "lavfi.astats.1.RMS_level", NULL,
388 AV_DICT_IGNORE_SUFFIX);
389
390 right_volume = av_dict_get(ffmpeg.filt_frame->metadata,
391 "lavfi.astats.2.RMS_level", NULL,
392 AV_DICT_IGNORE_SUFFIX);
393
394 ret = encode_audio_frame(&ffmpeg);
395 av_frame_unref(ffmpeg.filt_frame);
396 }
397 av_frame_unref(ffmpeg.frame);
398
399 if (ret == AVERROR_EOF)
400 goto end;
401 }
402 }
403 }
404
405end:
406 if (ret < 0 && ret != AVERROR_EOF) {
407 printf("errror: %s\n", av_err2str(ret));
408 }
409
410 if (ffmpeg.packet)
411 av_packet_free(&ffmpeg.packet);
412
413 if (ffmpeg.filter_graph)
414 avfilter_graph_free(&ffmpeg.filter_graph);
415
416 if (ffmpeg.dec_ctx) {
417 avcodec_free_context(&ffmpeg.dec_ctx);
418 }
419
420 if (ffmpeg.ifmt_ctx)
421 avformat_close_input(&ffmpeg.ifmt_ctx);
422
423 if (ffmpeg.enc_ctx) {
424 avcodec_free_context(&ffmpeg.enc_ctx);
425 }
426
427 if (ffmpeg.ofmt_ctx) {
428 if (ffmpeg.ofmt_ctx->pb)
429 avio_close(ffmpeg.ofmt_ctx->pb);
430 avformat_free_context(ffmpeg.ofmt_ctx);
431 }
432
433 if (ffmpeg.frame)
434 av_frame_free(&ffmpeg.frame);
435
436 if (ffmpeg.filt_frame)
437 av_frame_free(&ffmpeg.filt_frame);
438
439 return ret;
440}
441
442int main() {
443 int err = 0;
444
445 printf("Starting ffmpeg connection test..\n");
446
447 av_log_set_level(AV_LOG_INFO);
448 avdevice_register_all();
449
450 while (err == 0) {
451 err = runFfmpeg();
452 printf("One iteration done..\n");
453 sleep(WAITTIME);
454 }
455
456 return err;
457}