| 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 |
|
|---|
| 16 | typedef 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 |
|
|---|
| 31 | int 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 |
|
|---|
| 84 | int 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 |
|
|---|
| 167 | end:
|
|---|
| 168 | avfilter_inout_free(&inputs);
|
|---|
| 169 | avfilter_inout_free(&outputs);
|
|---|
| 170 |
|
|---|
| 171 | return ret;
|
|---|
| 172 | }
|
|---|
| 173 |
|
|---|
| 174 | int 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 |
|
|---|
| 213 | int 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 |
|
|---|
| 291 | cleanup:
|
|---|
| 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 |
|
|---|
| 299 | int 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(¤t, 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 |
|
|---|
| 405 | end:
|
|---|
| 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 |
|
|---|
| 442 | int 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 | }
|
|---|