|
| 1 | +// based on https://ffmpeg.org/doxygen/trunk/remuxing_8c-example.html |
| 2 | +#include <libavutil/timestamp.h> |
| 3 | +#include <libavformat/avformat.h> |
| 4 | + |
| 5 | +int main(int argc, char **argv) |
| 6 | +{ |
| 7 | + AVFormatContext *input_format_context = NULL, *output_format_context = NULL; |
| 8 | + AVPacket packet; |
| 9 | + const char *in_filename, *out_filename; |
| 10 | + int ret, i; |
| 11 | + int stream_index = 0; |
| 12 | + int *streams_list = NULL; |
| 13 | + int number_of_streams = 0; |
| 14 | + |
| 15 | + in_filename = argv[1]; |
| 16 | + out_filename = argv[2]; |
| 17 | + |
| 18 | + if ((ret = avformat_open_input(&input_format_context, in_filename, NULL, NULL)) < 0) { |
| 19 | + fprintf(stderr, "Could not open input file '%s'", in_filename); |
| 20 | + goto end; |
| 21 | + } |
| 22 | + if ((ret = avformat_find_stream_info(input_format_context, NULL)) < 0) { |
| 23 | + fprintf(stderr, "Failed to retrieve input stream information"); |
| 24 | + goto end; |
| 25 | + } |
| 26 | + |
| 27 | + avformat_alloc_output_context2(&output_format_context, NULL, NULL, out_filename); |
| 28 | + if (!output_format_context) { |
| 29 | + fprintf(stderr, "Could not create output context\n"); |
| 30 | + ret = AVERROR_UNKNOWN; |
| 31 | + goto end; |
| 32 | + } |
| 33 | + |
| 34 | + number_of_streams = input_format_context->nb_streams; |
| 35 | + streams_list = av_mallocz_array(number_of_streams, sizeof(*streams_list)); |
| 36 | + |
| 37 | + if (!streams_list) { |
| 38 | + ret = AVERROR(ENOMEM); |
| 39 | + goto end; |
| 40 | + } |
| 41 | + |
| 42 | + for (i = 0; i < input_format_context->nb_streams; i++) { |
| 43 | + AVStream *out_stream; |
| 44 | + AVStream *in_stream = input_format_context->streams[i]; |
| 45 | + AVCodecParameters *in_codecpar = in_stream->codecpar; |
| 46 | + if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO && |
| 47 | + in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO && |
| 48 | + in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) { |
| 49 | + streams_list[i] = -1; |
| 50 | + continue; |
| 51 | + } |
| 52 | + streams_list[i] = stream_index++; |
| 53 | + out_stream = avformat_new_stream(output_format_context, NULL); |
| 54 | + if (!out_stream) { |
| 55 | + fprintf(stderr, "Failed allocating output stream\n"); |
| 56 | + ret = AVERROR_UNKNOWN; |
| 57 | + goto end; |
| 58 | + } |
| 59 | + ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar); |
| 60 | + if (ret < 0) { |
| 61 | + fprintf(stderr, "Failed to copy codec parameters\n"); |
| 62 | + goto end; |
| 63 | + } |
| 64 | + } |
| 65 | + // https://ffmpeg.org/doxygen/trunk/group__lavf__misc.html#gae2645941f2dc779c307eb6314fd39f10 |
| 66 | + av_dump_format(output_format_context, 0, out_filename, 1); |
| 67 | + |
| 68 | + // unless it's a no file (we'll talk later about that) write to the disk (FLAG_WRITE) |
| 69 | + // but basically it's a way to save the file to a buffer so you can store it |
| 70 | + // wherever you want. |
| 71 | + if (!(output_format_context->oformat->flags & AVFMT_NOFILE)) { |
| 72 | + ret = avio_open(&output_format_context->pb, out_filename, AVIO_FLAG_WRITE); |
| 73 | + if (ret < 0) { |
| 74 | + fprintf(stderr, "Could not open output file '%s'", out_filename); |
| 75 | + goto end; |
| 76 | + } |
| 77 | + } |
| 78 | + // https://ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga18b7b10bb5b94c4842de18166bc677cb |
| 79 | + ret = avformat_write_header(output_format_context, NULL); |
| 80 | + if (ret < 0) { |
| 81 | + fprintf(stderr, "Error occurred when opening output file\n"); |
| 82 | + goto end; |
| 83 | + } |
| 84 | + while (1) { |
| 85 | + AVStream *in_stream, *out_stream; |
| 86 | + ret = av_read_frame(input_format_context, &packet); |
| 87 | + if (ret < 0) |
| 88 | + break; |
| 89 | + in_stream = input_format_context->streams[packet.stream_index]; |
| 90 | + if (packet.stream_index >= number_of_streams || streams_list[packet.stream_index] < 0) { |
| 91 | + av_packet_unref(&packet); |
| 92 | + continue; |
| 93 | + } |
| 94 | + packet.stream_index = streams_list[packet.stream_index]; |
| 95 | + out_stream = output_format_context->streams[packet.stream_index]; |
| 96 | + /* copy packet */ |
| 97 | + packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); |
| 98 | + packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); |
| 99 | + packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base); |
| 100 | + // https://ffmpeg.org/doxygen/trunk/structAVPacket.html#ab5793d8195cf4789dfb3913b7a693903 |
| 101 | + packet.pos = -1; |
| 102 | + |
| 103 | + //https://ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga37352ed2c63493c38219d935e71db6c1 |
| 104 | + ret = av_interleaved_write_frame(output_format_context, &packet); |
| 105 | + if (ret < 0) { |
| 106 | + fprintf(stderr, "Error muxing packet\n"); |
| 107 | + break; |
| 108 | + } |
| 109 | + av_packet_unref(&packet); |
| 110 | + } |
| 111 | + //https://ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga7f14007e7dc8f481f054b21614dfec13 |
| 112 | + av_write_trailer(output_format_context); |
| 113 | +end: |
| 114 | + avformat_close_input(&input_format_context); |
| 115 | + /* close output */ |
| 116 | + if (output_format_context && !(output_format_context->oformat->flags & AVFMT_NOFILE)) |
| 117 | + avio_closep(&output_format_context->pb); |
| 118 | + avformat_free_context(output_format_context); |
| 119 | + av_freep(&streams_list); |
| 120 | + if (ret < 0 && ret != AVERROR_EOF) { |
| 121 | + fprintf(stderr, "Error occurred: %s\n", av_err2str(ret)); |
| 122 | + return 1; |
| 123 | + } |
| 124 | + return 0; |
| 125 | +} |
| 126 | + |
0 commit comments