Skip to content

Commit 5e7e141

Browse files
Merge pull request #35 from leandromoreira/remuxing-chapter
Remuxing chapter
2 parents 6563e98 + 3f44f07 commit 5e7e141

2 files changed

Lines changed: 152 additions & 0 deletions

File tree

2_remuxing.c

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
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+
int fragmented_mp4_options = 0;
15+
16+
if (argc < 3) {
17+
printf("You need to pass at least two parameters.\n");
18+
return -1;
19+
} else if (argc == 4) {
20+
fragmented_mp4_options = 1;
21+
}
22+
23+
in_filename = argv[1];
24+
out_filename = argv[2];
25+
26+
if ((ret = avformat_open_input(&input_format_context, in_filename, NULL, NULL)) < 0) {
27+
fprintf(stderr, "Could not open input file '%s'", in_filename);
28+
goto end;
29+
}
30+
if ((ret = avformat_find_stream_info(input_format_context, NULL)) < 0) {
31+
fprintf(stderr, "Failed to retrieve input stream information");
32+
goto end;
33+
}
34+
35+
avformat_alloc_output_context2(&output_format_context, NULL, NULL, out_filename);
36+
if (!output_format_context) {
37+
fprintf(stderr, "Could not create output context\n");
38+
ret = AVERROR_UNKNOWN;
39+
goto end;
40+
}
41+
42+
number_of_streams = input_format_context->nb_streams;
43+
streams_list = av_mallocz_array(number_of_streams, sizeof(*streams_list));
44+
45+
if (!streams_list) {
46+
ret = AVERROR(ENOMEM);
47+
goto end;
48+
}
49+
50+
for (i = 0; i < input_format_context->nb_streams; i++) {
51+
AVStream *out_stream;
52+
AVStream *in_stream = input_format_context->streams[i];
53+
AVCodecParameters *in_codecpar = in_stream->codecpar;
54+
if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
55+
in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
56+
in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
57+
streams_list[i] = -1;
58+
continue;
59+
}
60+
streams_list[i] = stream_index++;
61+
out_stream = avformat_new_stream(output_format_context, NULL);
62+
if (!out_stream) {
63+
fprintf(stderr, "Failed allocating output stream\n");
64+
ret = AVERROR_UNKNOWN;
65+
goto end;
66+
}
67+
ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
68+
if (ret < 0) {
69+
fprintf(stderr, "Failed to copy codec parameters\n");
70+
goto end;
71+
}
72+
}
73+
// https://ffmpeg.org/doxygen/trunk/group__lavf__misc.html#gae2645941f2dc779c307eb6314fd39f10
74+
av_dump_format(output_format_context, 0, out_filename, 1);
75+
76+
// unless it's a no file (we'll talk later about that) write to the disk (FLAG_WRITE)
77+
// but basically it's a way to save the file to a buffer so you can store it
78+
// wherever you want.
79+
if (!(output_format_context->oformat->flags & AVFMT_NOFILE)) {
80+
ret = avio_open(&output_format_context->pb, out_filename, AVIO_FLAG_WRITE);
81+
if (ret < 0) {
82+
fprintf(stderr, "Could not open output file '%s'", out_filename);
83+
goto end;
84+
}
85+
}
86+
AVDictionary* opts = NULL;
87+
88+
if (fragmented_mp4_options) {
89+
// https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API/Transcoding_assets_for_MSE
90+
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov+default_base_moof", 0);
91+
}
92+
// https://ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga18b7b10bb5b94c4842de18166bc677cb
93+
ret = avformat_write_header(output_format_context, &opts);
94+
if (ret < 0) {
95+
fprintf(stderr, "Error occurred when opening output file\n");
96+
goto end;
97+
}
98+
while (1) {
99+
AVStream *in_stream, *out_stream;
100+
ret = av_read_frame(input_format_context, &packet);
101+
if (ret < 0)
102+
break;
103+
in_stream = input_format_context->streams[packet.stream_index];
104+
if (packet.stream_index >= number_of_streams || streams_list[packet.stream_index] < 0) {
105+
av_packet_unref(&packet);
106+
continue;
107+
}
108+
packet.stream_index = streams_list[packet.stream_index];
109+
out_stream = output_format_context->streams[packet.stream_index];
110+
/* copy packet */
111+
packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
112+
packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
113+
packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
114+
// https://ffmpeg.org/doxygen/trunk/structAVPacket.html#ab5793d8195cf4789dfb3913b7a693903
115+
packet.pos = -1;
116+
117+
//https://ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga37352ed2c63493c38219d935e71db6c1
118+
ret = av_interleaved_write_frame(output_format_context, &packet);
119+
if (ret < 0) {
120+
fprintf(stderr, "Error muxing packet\n");
121+
break;
122+
}
123+
av_packet_unref(&packet);
124+
}
125+
//https://ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga7f14007e7dc8f481f054b21614dfec13
126+
av_write_trailer(output_format_context);
127+
end:
128+
avformat_close_input(&input_format_context);
129+
/* close output */
130+
if (output_format_context && !(output_format_context->oformat->flags & AVFMT_NOFILE))
131+
avio_closep(&output_format_context->pb);
132+
avformat_free_context(output_format_context);
133+
av_freep(&streams_list);
134+
if (ret < 0 && ret != AVERROR_EOF) {
135+
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
136+
return 1;
137+
}
138+
return 0;
139+
}
140+

Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,15 @@ make_hello: clean
99

1010
run_hello: make_hello
1111
docker run -w /files --rm -it -v `pwd`:/files leandromoreira/ffmpeg-devel /files/build/hello /files/small_bunny_1080p_60fps.mp4
12+
13+
make_remuxing: clean
14+
docker run -w /files --rm -it -v `pwd`:/files leandromoreira/ffmpeg-devel \
15+
gcc -L/opt/ffmpeg/lib -I/opt/ffmpeg/include/ /files/2_remuxing.c \
16+
-lavcodec -lavformat -lavfilter -lavdevice -lswresample -lswscale -lavutil \
17+
-o /files/build/remuxing
18+
19+
run_remuxing_ts: make_remuxing
20+
docker run -w /files --rm -it -v `pwd`:/files leandromoreira/ffmpeg-devel /files/build/remuxing /files/small_bunny_1080p_60fps.mp4 /files/remuxed_small_bunny_1080p_60fps.ts
21+
22+
run_remuxing_fragmented_mp4: make_remuxing
23+
docker run -w /files --rm -it -v `pwd`:/files leandromoreira/ffmpeg-devel /files/build/remuxing /files/small_bunny_1080p_60fps.mp4 /files/fragmented_small_bunny_1080p_60fps.mp4 fragmented

0 commit comments

Comments
 (0)