FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/rmenc.c
Date: 2024-05-26 22:00:00
Exec Total Coverage
Lines: 250 268 93.3%
Functions: 9 9 100.0%
Branches: 68 80 85.0%

Line Branch Exec Source
1 /*
2 * "Real" compatible muxer.
3 * Copyright (c) 2000, 2001 Fabrice Bellard
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 #include "avformat.h"
22 #include "avio_internal.h"
23 #include "mux.h"
24 #include "rm.h"
25 #include "libavutil/dict.h"
26
27 typedef struct StreamInfo {
28 int nb_packets;
29 int packet_total_size;
30 int packet_max_size;
31 /* codec related output */
32 int bit_rate;
33 AVRational frame_rate;
34 int nb_frames; /* current frame number */
35 int total_frames; /* total number of frames */
36 int num;
37 AVCodecParameters *par;
38 } StreamInfo;
39
40 typedef struct RMMuxContext {
41 StreamInfo streams[2];
42 StreamInfo *audio_stream, *video_stream;
43 int data_pos; /* position of the data after the header */
44 } RMMuxContext;
45
46 /* in ms */
47 #define BUFFER_DURATION 0
48 /* the header needs at most 7 + 4 + 12 B */
49 #define MAX_HEADER_SIZE (7 + 4 + 12)
50 /* UINT16_MAX is the maximal chunk size */
51 #define MAX_PACKET_SIZE (UINT16_MAX - MAX_HEADER_SIZE)
52
53
54 64 static void put_str(AVIOContext *s, const char *tag)
55 {
56 64 avio_wb16(s,strlen(tag));
57
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 64 times.
80 while (*tag) {
58 16 avio_w8(s, *tag++);
59 }
60 64 }
61
62 40 static void put_str8(AVIOContext *s, const char *tag)
63 {
64 40 avio_w8(s, strlen(tag));
65
2/2
✓ Branch 0 taken 664 times.
✓ Branch 1 taken 40 times.
704 while (*tag) {
66 664 avio_w8(s, *tag++);
67 }
68 40 }
69
70 16 static int rv10_write_header(AVFormatContext *ctx,
71 int data_size, int index_pos)
72 {
73 16 RMMuxContext *rm = ctx->priv_data;
74 16 AVIOContext *s = ctx->pb;
75 StreamInfo *stream;
76 const char *desc, *mimetype;
77 int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i;
78 int bit_rate, v, duration, flags;
79 int data_offset;
80 AVDictionaryEntry *tag;
81
82 16 ffio_wfourcc(s, ".RMF");
83 16 avio_wb32(s,18); /* header size */
84 16 avio_wb16(s,0);
85 16 avio_wb32(s,0);
86 16 avio_wb32(s,4 + ctx->nb_streams); /* num headers */
87
88 16 ffio_wfourcc(s,"PROP");
89 16 avio_wb32(s, 50);
90 16 avio_wb16(s, 0);
91 16 packet_max_size = 0;
92 16 packet_total_size = 0;
93 16 nb_packets = 0;
94 16 bit_rate = 0;
95 16 duration = 0;
96
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 16 times.
34 for(i=0;i<ctx->nb_streams;i++) {
97 18 StreamInfo *stream = &rm->streams[i];
98 18 bit_rate += stream->bit_rate;
99
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2 times.
18 if (stream->packet_max_size > packet_max_size)
100 16 packet_max_size = stream->packet_max_size;
101 18 nb_packets += stream->nb_packets;
102 18 packet_total_size += stream->packet_total_size;
103 /* select maximum duration */
104 18 v = av_rescale_q_rnd(stream->total_frames, (AVRational){1000, 1}, stream->frame_rate, AV_ROUND_ZERO);
105
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if (v > duration)
106 8 duration = v;
107 }
108 16 avio_wb32(s, bit_rate); /* max bit rate */
109 16 avio_wb32(s, bit_rate); /* avg bit rate */
110 16 avio_wb32(s, packet_max_size); /* max packet size */
111
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (nb_packets > 0)
112 8 packet_avg_size = packet_total_size / nb_packets;
113 else
114 8 packet_avg_size = 0;
115 16 avio_wb32(s, packet_avg_size); /* avg packet size */
116 16 avio_wb32(s, nb_packets); /* num packets */
117 16 avio_wb32(s, duration); /* duration */
118 16 avio_wb32(s, BUFFER_DURATION); /* preroll */
119 16 avio_wb32(s, index_pos); /* index offset */
120 /* computation of data the data offset */
121 16 data_offset = avio_tell(s);
122 16 avio_wb32(s, 0); /* data offset : will be patched after */
123 16 avio_wb16(s, ctx->nb_streams); /* num streams */
124 16 flags = 1 | 2; /* save allowed & perfect play */
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!(s->seekable & AVIO_SEEKABLE_NORMAL))
126 flags |= 4; /* live broadcast */
127 16 avio_wb16(s, flags);
128
129 /* comments */
130
131 16 ffio_wfourcc(s,"CONT");
132 16 size = 4 * 2 + 10;
133
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 16 times.
80 for(i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) {
134 64 tag = av_dict_get(ctx->metadata, ff_rm_metadata[i], NULL, 0);
135
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 62 times.
64 if(tag) size += strlen(tag->value);
136 }
137 16 avio_wb32(s,size);
138 16 avio_wb16(s,0);
139
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 16 times.
80 for(i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) {
140 64 tag = av_dict_get(ctx->metadata, ff_rm_metadata[i], NULL, 0);
141
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 62 times.
64 put_str(s, tag ? tag->value : "");
142 }
143
144
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 16 times.
34 for(i=0;i<ctx->nb_streams;i++) {
145 int codec_data_size;
146
147 18 stream = &rm->streams[i];
148
149
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
18 if (stream->par->codec_type == AVMEDIA_TYPE_AUDIO) {
150 4 desc = "The Audio Stream";
151 4 mimetype = "audio/x-pn-realaudio";
152 4 codec_data_size = 73;
153 } else {
154 14 desc = "The Video Stream";
155 14 mimetype = "video/x-pn-realvideo";
156 14 codec_data_size = 34;
157 }
158
159 18 ffio_wfourcc(s,"MDPR");
160 18 size = 10 + 9 * 4 + strlen(desc) + strlen(mimetype) + codec_data_size;
161 18 avio_wb32(s, size);
162 18 avio_wb16(s, 0);
163
164 18 avio_wb16(s, i); /* stream number */
165 18 avio_wb32(s, stream->bit_rate); /* max bit rate */
166 18 avio_wb32(s, stream->bit_rate); /* avg bit rate */
167 18 avio_wb32(s, stream->packet_max_size); /* max packet size */
168
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (stream->nb_packets > 0)
169 9 packet_avg_size = stream->packet_total_size /
170 9 stream->nb_packets;
171 else
172 9 packet_avg_size = 0;
173 18 avio_wb32(s, packet_avg_size); /* avg packet size */
174 18 avio_wb32(s, 0); /* start time */
175 18 avio_wb32(s, BUFFER_DURATION); /* preroll */
176 /* duration */
177
3/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 9 times.
18 if (!(s->seekable & AVIO_SEEKABLE_NORMAL) || !stream->total_frames)
178 9 avio_wb32(s, (int)(3600 * 1000));
179 else
180 9 avio_wb32(s, av_rescale_q_rnd(stream->total_frames, (AVRational){1000, 1}, stream->frame_rate, AV_ROUND_ZERO));
181 18 put_str8(s, desc);
182 18 put_str8(s, mimetype);
183 18 avio_wb32(s, codec_data_size);
184
185
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
18 if (stream->par->codec_type == AVMEDIA_TYPE_AUDIO) {
186 int coded_frame_size, fscode, sample_rate;
187 4 int frame_size = av_get_audio_frame_duration2(stream->par, 0);
188 4 sample_rate = stream->par->sample_rate;
189 4 coded_frame_size = (stream->par->bit_rate *
190 4 frame_size) / (8 * sample_rate);
191 /* audio codec info */
192 4 avio_write(s, ".ra", 3);
193 4 avio_w8(s, 0xfd);
194 4 avio_wb32(s, 0x00040000); /* version */
195 4 ffio_wfourcc(s, ".ra4");
196 4 avio_wb32(s, 0x01b53530); /* stream length */
197 4 avio_wb16(s, 4); /* unknown */
198 4 avio_wb32(s, 0x39); /* header size */
199
200
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 switch(sample_rate) {
201 case 48000:
202 case 24000:
203 case 12000:
204 fscode = 1;
205 break;
206 2 default:
207 case 44100:
208 case 22050:
209 case 11025:
210 2 fscode = 2;
211 2 break;
212 2 case 32000:
213 case 16000:
214 case 8000:
215 2 fscode = 3;
216 }
217 4 avio_wb16(s, fscode); /* codec additional info, for AC-3, seems
218 to be a frequency code */
219 /* special hack to compensate rounding errors... */
220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (coded_frame_size == 557)
221 coded_frame_size--;
222 4 avio_wb32(s, coded_frame_size); /* frame length */
223 4 avio_wb32(s, 0x51540); /* unknown */
224 4 avio_wb32(s, stream->par->bit_rate / 8 * 60); /* bytes per minute */
225 4 avio_wb32(s, stream->par->bit_rate / 8 * 60); /* bytes per minute */
226 4 avio_wb16(s, 0x01);
227 /* frame length : seems to be very important */
228 4 avio_wb16(s, coded_frame_size);
229 4 avio_wb32(s, 0); /* unknown */
230 4 avio_wb16(s, stream->par->sample_rate); /* sample rate */
231 4 avio_wb32(s, 0x10); /* unknown */
232 4 avio_wb16(s, stream->par->ch_layout.nb_channels);
233 4 put_str8(s, "Int0"); /* codec name */
234
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (stream->par->codec_tag) {
235 4 avio_w8(s, 4); /* tag length */
236 4 avio_wl32(s, stream->par->codec_tag);
237 } else {
238 av_log(ctx, AV_LOG_ERROR, "Invalid codec tag\n");
239 return -1;
240 }
241 4 avio_wb16(s, 0); /* title length */
242 4 avio_wb16(s, 0); /* author length */
243 4 avio_wb16(s, 0); /* copyright length */
244 4 avio_w8(s, 0); /* end of header */
245 } else {
246 /* video codec info */
247 14 avio_wb32(s,34); /* size */
248 14 ffio_wfourcc(s, "VIDO");
249
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 if(stream->par->codec_id == AV_CODEC_ID_RV10)
250 8 ffio_wfourcc(s,"RV10");
251 else
252 6 ffio_wfourcc(s,"RV20");
253 14 avio_wb16(s, stream->par->width);
254 14 avio_wb16(s, stream->par->height);
255
256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (stream->frame_rate.num / stream->frame_rate.den > 65535) {
257 av_log(s, AV_LOG_ERROR, "Frame rate %d is too high\n", stream->frame_rate.num / stream->frame_rate.den);
258 return AVERROR(EINVAL);
259 }
260
261 14 avio_wb16(s, stream->frame_rate.num / stream->frame_rate.den); /* frames per seconds ? */
262 14 avio_wb32(s,0); /* unknown meaning */
263 14 avio_wb16(s, stream->frame_rate.num / stream->frame_rate.den); /* unknown meaning */
264 14 avio_wb32(s,0); /* unknown meaning */
265 14 avio_wb16(s, 8); /* unknown meaning */
266 /* Seems to be the codec version: only use basic H.263. The next
267 versions seems to add a differential DC coding as in
268 MPEG... nothing new under the sun. */
269
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 if(stream->par->codec_id == AV_CODEC_ID_RV10)
270 8 avio_wb32(s,0x10000000);
271 else
272 6 avio_wb32(s,0x20103001);
273 //avio_wb32(s,0x10003000);
274 }
275 }
276
277 /* patch data offset field */
278 16 rm->data_pos = avio_tell(s);
279
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 if (avio_seek(s, data_offset, SEEK_SET) >= 0) {
280 16 avio_wb32(s, rm->data_pos);
281 16 avio_seek(s, rm->data_pos, SEEK_SET);
282 }
283
284 /* data stream */
285 16 ffio_wfourcc(s, "DATA");
286 16 avio_wb32(s,data_size + 10 + 8);
287 16 avio_wb16(s,0);
288
289 16 avio_wb32(s, nb_packets); /* number of packets */
290 16 avio_wb32(s,0); /* next data header */
291 16 return 0;
292 }
293
294 655 static void write_packet_header(AVFormatContext *ctx, StreamInfo *stream,
295 int length, int key_frame)
296 {
297 int timestamp;
298 655 AVIOContext *s = ctx->pb;
299
300 655 stream->nb_packets++;
301 655 stream->packet_total_size += length;
302
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 627 times.
655 if (length > stream->packet_max_size)
303 28 stream->packet_max_size = length;
304
305 655 avio_wb16(s,0); /* version */
306 655 avio_wb16(s,length + 12);
307 655 avio_wb16(s, stream->num); /* stream number */
308 655 timestamp = av_rescale_q_rnd(stream->nb_frames, (AVRational){1000, 1}, stream->frame_rate, AV_ROUND_ZERO);
309 655 avio_wb32(s, timestamp); /* timestamp */
310 655 avio_w8(s, 0); /* reserved */
311
2/2
✓ Branch 0 taken 363 times.
✓ Branch 1 taken 292 times.
655 avio_w8(s, key_frame ? 2 : 0); /* flags */
312 655 }
313
314 8 static int rm_write_header(AVFormatContext *s)
315 {
316 8 RMMuxContext *rm = s->priv_data;
317 StreamInfo *stream;
318 int n;
319 AVCodecParameters *par;
320
321
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (s->nb_streams > 2) {
322 av_log(s, AV_LOG_ERROR, "At most 2 streams are currently supported for muxing in RM\n");
323 return AVERROR_PATCHWELCOME;
324 }
325
326
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 8 times.
17 for(n=0;n<s->nb_streams;n++) {
327 9 AVStream *st = s->streams[n];
328 int frame_size;
329
330 9 s->streams[n]->id = n;
331 9 par = s->streams[n]->codecpar;
332 9 stream = &rm->streams[n];
333 9 memset(stream, 0, sizeof(StreamInfo));
334 9 stream->num = n;
335 9 stream->bit_rate = par->bit_rate;
336 9 stream->par = par;
337
338
2/3
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
9 switch (par->codec_type) {
339 2 case AVMEDIA_TYPE_AUDIO:
340 2 rm->audio_stream = stream;
341 2 frame_size = av_get_audio_frame_duration2(par, 0);
342 2 stream->frame_rate = (AVRational){par->sample_rate, frame_size};
343 /* XXX: dummy values */
344 2 stream->packet_max_size = 1024;
345 2 stream->nb_packets = 0;
346 2 stream->total_frames = stream->nb_packets;
347 9 break;
348 7 case AVMEDIA_TYPE_VIDEO:
349 7 rm->video_stream = stream;
350 // TODO: should be avg_frame_rate
351 7 stream->frame_rate = av_inv_q(st->time_base);
352 /* XXX: dummy values */
353 7 stream->packet_max_size = 4096;
354 7 stream->nb_packets = 0;
355 7 stream->total_frames = stream->nb_packets;
356 7 break;
357 default:
358 return -1;
359 }
360 }
361
362
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if (rv10_write_header(s, 0, 0))
363 return AVERROR_INVALIDDATA;
364 8 return 0;
365 }
366
367 330 static int rm_write_audio(AVFormatContext *s, const uint8_t *buf, int size, int flags)
368 {
369 330 RMMuxContext *rm = s->priv_data;
370 330 AVIOContext *pb = s->pb;
371 330 StreamInfo *stream = rm->audio_stream;
372 int i;
373
374 330 write_packet_header(s, stream, size, !!(flags & AV_PKT_FLAG_KEY));
375
376
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 301 times.
330 if (stream->par->codec_id == AV_CODEC_ID_AC3) {
377 /* for AC-3, the words seem to be reversed */
378
2/2
✓ Branch 0 taken 4040 times.
✓ Branch 1 taken 29 times.
4069 for (i = 0; i < size; i += 2) {
379 4040 avio_w8(pb, buf[i + 1]);
380 4040 avio_w8(pb, buf[i]);
381 }
382 } else {
383 301 avio_write(pb, buf, size);
384 }
385 330 stream->nb_frames++;
386 330 return 0;
387 }
388
389 325 static int rm_write_video(AVFormatContext *s, const uint8_t *buf, int size, int flags)
390 {
391 325 RMMuxContext *rm = s->priv_data;
392 325 AVIOContext *pb = s->pb;
393 325 StreamInfo *stream = rm->video_stream;
394 325 int key_frame = !!(flags & AV_PKT_FLAG_KEY);
395
396 /* XXX: this is incorrect: should be a parameter */
397
398 /* Well, I spent some time finding the meaning of these bits. I am
399 not sure I understood everything, but it works !! */
400
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
325 if (size > MAX_PACKET_SIZE) {
401 av_log(s, AV_LOG_ERROR, "Muxing packets larger than 64 kB (%d) is not supported\n", size);
402 return AVERROR_PATCHWELCOME;
403 }
404
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 311 times.
325 write_packet_header(s, stream, size + 7 + (size >= 0x4000)*4, key_frame);
405 /* bit 7: '1' if final packet of a frame converted in several packets */
406 325 avio_w8(pb, 0x81);
407 /* bit 7: '1' if I-frame. bits 6..0 : sequence number in current
408 frame starting from 1 */
409
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 292 times.
325 if (key_frame) {
410 33 avio_w8(pb, 0x81);
411 } else {
412 292 avio_w8(pb, 0x01);
413 }
414
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 311 times.
325 if(size >= 0x4000){
415 14 avio_wb32(pb, size); /* total frame size */
416 14 avio_wb32(pb, size); /* offset from the start or the end */
417 }else{
418 311 avio_wb16(pb, 0x4000 | size); /* total frame size */
419 311 avio_wb16(pb, 0x4000 | size); /* offset from the start or the end */
420 }
421 325 avio_w8(pb, stream->nb_frames & 0xff);
422
423 325 avio_write(pb, buf, size);
424
425 325 stream->nb_frames++;
426 325 return 0;
427 }
428
429 655 static int rm_write_packet(AVFormatContext *s, AVPacket *pkt)
430 {
431
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 325 times.
655 if (s->streams[pkt->stream_index]->codecpar->codec_type ==
432 AVMEDIA_TYPE_AUDIO)
433 330 return rm_write_audio(s, pkt->data, pkt->size, pkt->flags);
434 else
435 325 return rm_write_video(s, pkt->data, pkt->size, pkt->flags);
436 }
437
438 8 static int rm_write_trailer(AVFormatContext *s)
439 {
440 8 RMMuxContext *rm = s->priv_data;
441 int data_size, index_pos, i;
442 8 AVIOContext *pb = s->pb;
443
444
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
445 /* end of file: finish to write header */
446 8 index_pos = avio_tell(pb);
447 8 data_size = index_pos - rm->data_pos;
448
449 /* FIXME: write index */
450
451 /* undocumented end header */
452 8 avio_wb32(pb, 0);
453 8 avio_wb32(pb, 0);
454
455 8 avio_seek(pb, 0, SEEK_SET);
456
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 8 times.
17 for(i=0;i<s->nb_streams;i++)
457 9 rm->streams[i].total_frames = rm->streams[i].nb_frames;
458 8 rv10_write_header(s, data_size, 0);
459 } else {
460 /* undocumented end header */
461 avio_wb32(pb, 0);
462 avio_wb32(pb, 0);
463 }
464
465 8 return 0;
466 }
467
468
469 const FFOutputFormat ff_rm_muxer = {
470 .p.name = "rm",
471 .p.long_name = NULL_IF_CONFIG_SMALL("RealMedia"),
472 .p.mime_type = "application/vnd.rn-realmedia",
473 .p.extensions = "rm,ra",
474 .priv_data_size = sizeof(RMMuxContext),
475 .p.audio_codec = AV_CODEC_ID_AC3,
476 .p.video_codec = AV_CODEC_ID_RV10,
477 .write_header = rm_write_header,
478 .write_packet = rm_write_packet,
479 .write_trailer = rm_write_trailer,
480 .p.codec_tag = (const AVCodecTag* const []){ ff_rm_codec_tags, 0 },
481 };
482