FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/bsf/mpeg4_unpack_bframes.c
Date: 2024-05-03 15:42:48
Exec Total Coverage
Lines: 63 70 90.0%
Functions: 4 4 100.0%
Branches: 40 50 80.0%

Line Branch Exec Source
1 /*
2 * Bitstream filter for unpacking DivX-style packed B-frames in MPEG-4 (divx_packed)
3 * Copyright (c) 2015 Andreas Cadhalpun <Andreas.Cadhalpun@googlemail.com>
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
22 #include "bsf.h"
23 #include "bsf_internal.h"
24 #include "mpeg4videodefs.h"
25 #include "startcode.h"
26
27 typedef struct UnpackBFramesBSFContext {
28 AVBufferRef *b_frame_ref;
29 } UnpackBFramesBSFContext;
30
31 /* determine the position of the packed marker in the userdata,
32 * the number of VOPs and the position of the second VOP */
33 16 static void scan_buffer(const uint8_t *buf, int buf_size,
34 int *pos_p, int *nb_vop, int *pos_vop2) {
35 uint32_t startcode;
36 16 const uint8_t *end = buf + buf_size, *pos = buf;
37
38
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
64 while (pos < end) {
39 48 startcode = -1;
40 48 pos = avpriv_find_start_code(pos, end, &startcode);
41
42
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
48 if (startcode == USER_DATA_STARTCODE && pos_p) {
43 /* check if the (DivX) userdata string ends with 'p' (packed) */
44
4/4
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 286 times.
✓ Branch 3 taken 1 times.
290 for (int i = 0; i < 255 && pos + i + 1 < end; i++) {
45
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 283 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
286 if (pos[i] == 'p' && pos[i + 1] == '\0') {
46 2 *pos_p = pos + i - buf;
47 2 break;
48 }
49 }
50
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
44 } else if (startcode == VOP_STARTCODE && nb_vop) {
51 20 *nb_vop += 1;
52
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
20 if (*nb_vop == 2 && pos_vop2) {
53 5 *pos_vop2 = pos - buf - 4; /* subtract 4 bytes startcode */
54 }
55 }
56 }
57 16 }
58
59 31 static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *pkt)
60 {
61 31 UnpackBFramesBSFContext *s = ctx->priv_data;
62 31 int pos_p = -1, nb_vop = 0, pos_vop2 = -1, ret = 0;
63
64 31 ret = ff_bsf_get_packet_ref(ctx, pkt);
65
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 15 times.
31 if (ret < 0)
66 16 return ret;
67
68 15 scan_buffer(pkt->data, pkt->size, &pos_p, &nb_vop, &pos_vop2);
69 15 av_log(ctx, AV_LOG_DEBUG, "Found %d VOP startcode(s) in this packet.\n", nb_vop);
70
71
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 10 times.
15 if (pos_vop2 >= 0) {
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (s->b_frame_ref) {
73 av_log(ctx, AV_LOG_WARNING,
74 "Missing one N-VOP packet, discarding one B-frame.\n");
75 av_buffer_unref(&s->b_frame_ref);
76 }
77 /* store a reference to the packed B-frame's data in the BSFContext */
78 5 s->b_frame_ref = av_buffer_ref(pkt->buf);
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!s->b_frame_ref) {
80 ret = AVERROR(ENOMEM);
81 goto fail;
82 }
83 5 s->b_frame_ref->data = pkt->data + pos_vop2;
84 5 s->b_frame_ref->size = pkt->size - pos_vop2;
85 }
86
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (nb_vop > 2) {
88 av_log(ctx, AV_LOG_WARNING,
89 "Found %d VOP headers in one packet, only unpacking one.\n", nb_vop);
90 }
91
92
4/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 3 times.
22 if (nb_vop == 1 && s->b_frame_ref) {
93 7 AVBufferRef *tmp = pkt->buf;
94
95 /* make tmp accurately reflect the packet's data */
96 7 tmp->data = pkt->data;
97 7 tmp->size = pkt->size;
98
99 /* replace data in packet with stored data */
100 7 pkt->buf = s->b_frame_ref;
101 7 pkt->data = s->b_frame_ref->data;
102 7 pkt->size = s->b_frame_ref->size;
103
104 /* store reference to data into BSFContext */
105 7 s->b_frame_ref = tmp;
106
107
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (s->b_frame_ref->size <= MAX_NVOP_SIZE) {
108 /* N-VOP - discard stored data */
109 4 av_log(ctx, AV_LOG_DEBUG, "Skipping N-VOP.\n");
110 4 av_buffer_unref(&s->b_frame_ref);
111 }
112
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 } else if (nb_vop >= 2) {
113 /* use first frame of the packet */
114 5 pkt->size = pos_vop2;
115
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 } else if (pos_p >= 0) {
116 1 ret = av_packet_make_writable(pkt);
117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
118 goto fail;
119 1 av_log(ctx, AV_LOG_DEBUG, "Updating DivX userdata (remove trailing 'p').\n");
120 /* remove 'p' (packed) from the end of the (DivX) userdata string */
121 1 pkt->data[pos_p] = '\0';
122 } else {
123 /* use packet as is */
124 }
125
126 2 fail:
127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (ret < 0)
128 av_packet_unref(pkt);
129
130 15 return ret;
131 }
132
133 1 static int mpeg4_unpack_bframes_init(AVBSFContext *ctx)
134 {
135
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ctx->par_in->extradata) {
136 1 int pos_p_ext = -1;
137 1 scan_buffer(ctx->par_in->extradata, ctx->par_in->extradata_size, &pos_p_ext, NULL, NULL);
138
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pos_p_ext >= 0) {
139 1 av_log(ctx, AV_LOG_DEBUG,
140 "Updating DivX userdata (remove trailing 'p') in extradata.\n");
141 1 ctx->par_out->extradata[pos_p_ext] = '\0';
142 }
143 }
144
145 1 return 0;
146 }
147
148 1 static void mpeg4_unpack_bframes_close_flush(AVBSFContext *bsfc)
149 {
150 1 UnpackBFramesBSFContext *ctx = bsfc->priv_data;
151 1 av_buffer_unref(&ctx->b_frame_ref);
152 1 }
153
154 static const enum AVCodecID codec_ids[] = {
155 AV_CODEC_ID_MPEG4, AV_CODEC_ID_NONE,
156 };
157
158 const FFBitStreamFilter ff_mpeg4_unpack_bframes_bsf = {
159 .p.name = "mpeg4_unpack_bframes",
160 .p.codec_ids = codec_ids,
161 .priv_data_size = sizeof(UnpackBFramesBSFContext),
162 .init = mpeg4_unpack_bframes_init,
163 .filter = mpeg4_unpack_bframes_filter,
164 .flush = mpeg4_unpack_bframes_close_flush,
165 .close = mpeg4_unpack_bframes_close_flush,
166 };
167