FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/codecstring.c
Date: 2026-04-02 12:19:26
Exec Total Coverage
Lines: 78 120 65.0%
Functions: 2 3 66.7%
Branches: 51 96 53.1%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2014 Martin Storsjo
3 * Copyright (c) 2018 Akamai Technologies, Inc.
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 "libavutil/avstring.h"
23 #include "libavutil/bprint.h"
24 #include "libavutil/intreadwrite.h"
25 #include "libavutil/mem.h"
26 #include "libavutil/rational.h"
27
28 #include "av1.h"
29 #include "avc.h"
30 #include "avformat.h"
31 #include "internal.h"
32 #include "lcevc.h"
33 #include "nal.h"
34 #include "vpcc.h"
35
36 static const struct codec_string {
37 enum AVCodecID id;
38 char str[8];
39 } codecs[] = {
40 { AV_CODEC_ID_VP8, "vp8" },
41 { AV_CODEC_ID_VP9, "vp9" },
42 { AV_CODEC_ID_VORBIS, "vorbis" },
43 { AV_CODEC_ID_OPUS, "opus" },
44 { AV_CODEC_ID_FLAC, "flac" },
45 { AV_CODEC_ID_NONE }
46 };
47
48 static void set_vp9_codec_str(void *logctx, const AVCodecParameters *par,
49 const AVRational *frame_rate, AVBPrint *out)
50 {
51 VPCC vpcc;
52 int ret = ff_isom_get_vpcc_features(logctx, par, NULL, 0, frame_rate, &vpcc);
53 if (ret == 0) {
54 av_bprintf(out, "vp09.%02d.%02d.%02d",
55 vpcc.profile, vpcc.level, vpcc.bitdepth);
56 } else {
57 // Default to just vp9 in case of error while finding out profile or level
58 if (logctx)
59 av_log(logctx, AV_LOG_WARNING, "Could not find VP9 profile and/or level\n");
60 av_bprintf(out, "vp9");
61 }
62 }
63
64 390 int ff_make_codec_str(void *logctx, const AVCodecParameters *par,
65 const AVRational *frame_rate, struct AVBPrint *out)
66 {
67 int i;
68
69 // common Webm codecs are not part of RFC 6381
70
2/2
✓ Branch 0 taken 1908 times.
✓ Branch 1 taken 223 times.
2131 for (i = 0; codecs[i].id != AV_CODEC_ID_NONE; i++)
71
2/2
✓ Branch 0 taken 167 times.
✓ Branch 1 taken 1741 times.
1908 if (codecs[i].id == par->codec_id) {
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 if (codecs[i].id == AV_CODEC_ID_VP9) {
73 set_vp9_codec_str(logctx, par, frame_rate, out);
74 } else {
75 167 av_bprintf(out, "%s", codecs[i].str);
76 }
77 167 return 0;
78 }
79
80
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 204 times.
223 if (par->codec_id == AV_CODEC_ID_H264) {
81 // RFC 6381
82 19 uint8_t *data = par->extradata;
83
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 if (data) {
84 const uint8_t *p;
85
86
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
19 if (AV_RB32(data) == 0x01 && (data[4] & 0x1F) == 7)
87 2 p = &data[5];
88
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17 else if (AV_RB24(data) == 0x01 && (data[3] & 0x1F) == 7)
89 p = &data[4];
90
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 else if (data[0] == 0x01) /* avcC */
91 17 p = &data[1];
92 else
93 return AVERROR(EINVAL);
94 19 av_bprintf(out, "avc1.%02x%02x%02x", p[0], p[1], p[2]);
95 } else {
96 return AVERROR(EINVAL);
97 }
98
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 182 times.
204 } else if (par->codec_id == AV_CODEC_ID_HEVC) {
99 // 3GPP TS 26.244
100 22 uint8_t *data = par->extradata;
101 22 int profile = AV_PROFILE_UNKNOWN;
102 22 uint32_t profile_compatibility = AV_PROFILE_UNKNOWN;
103 22 char tier = 0;
104 22 int level = AV_LEVEL_UNKNOWN;
105 22 char constraints[8] = "";
106
107
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (par->profile != AV_PROFILE_UNKNOWN)
108 22 profile = par->profile;
109
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (par->level != AV_LEVEL_UNKNOWN)
110 22 level = par->level;
111
112 /* check the boundary of data which from current position is small than extradata_size */
113
3/4
✓ Branch 0 taken 2228 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2211 times.
✓ Branch 3 taken 17 times.
2228 while (data && (data - par->extradata + 19) < par->extradata_size) {
114 /* get HEVC SPS NAL and seek to profile_tier_level */
115
6/6
✓ Branch 0 taken 115 times.
✓ Branch 1 taken 2096 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 105 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 5 times.
2211 if (!(data[0] | data[1] | data[2]) && data[3] == 1 && ((data[4] & 0x7E) == 0x42)) {
116 uint8_t *rbsp_buf;
117 5 int remain_size = 0;
118 5 int rbsp_size = 0;
119 5 uint32_t profile_compatibility_flags = 0;
120 5 uint8_t high_nibble = 0;
121 /* skip start code + nalu header */
122 5 data += 6;
123 /* process by reference General NAL unit syntax */
124 5 remain_size = par->extradata_size - (data - par->extradata);
125 5 rbsp_buf = ff_nal_unit_extract_rbsp(data, remain_size, &rbsp_size, 0);
126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!rbsp_buf)
127 return AVERROR(EINVAL);
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (rbsp_size < 13) {
129 av_freep(&rbsp_buf);
130 5 break;
131 }
132 /* skip sps_video_parameter_set_id u(4),
133 * sps_max_sub_layers_minus1 u(3),
134 * and sps_temporal_id_nesting_flag u(1)
135 *
136 * TIER represents the general_tier_flag, with 'L' indicating the flag is 0,
137 * and 'H' indicating the flag is 1
138 */
139
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 tier = (rbsp_buf[1] & 0x20) == 0 ? 'L' : 'H';
140 5 profile = rbsp_buf[1] & 0x1f;
141 /* PROFILE_COMPATIBILITY is general_profile_compatibility_flags, but in reverse bit order,
142 * in a hexadecimal representation (leading zeroes may be omitted).
143 */
144 5 profile_compatibility_flags = AV_RB32(rbsp_buf + 2);
145 /* revise these bits to get the profile compatibility value */
146 5 profile_compatibility_flags = ((profile_compatibility_flags & 0x55555555U) << 1) | ((profile_compatibility_flags >> 1) & 0x55555555U);
147 5 profile_compatibility_flags = ((profile_compatibility_flags & 0x33333333U) << 2) | ((profile_compatibility_flags >> 2) & 0x33333333U);
148 5 profile_compatibility_flags = ((profile_compatibility_flags & 0x0F0F0F0FU) << 4) | ((profile_compatibility_flags >> 4) & 0x0F0F0F0FU);
149 5 profile_compatibility_flags = ((profile_compatibility_flags & 0x00FF00FFU) << 8) | ((profile_compatibility_flags >> 8) & 0x00FF00FFU);
150 5 profile_compatibility = (profile_compatibility_flags << 16) | (profile_compatibility_flags >> 16);
151 /* skip 8 + 8 + 32
152 * CONSTRAINTS is a hexadecimal representation of the general_constraint_indicator_flags.
153 * each byte is separated by a '.', and trailing zero bytes may be omitted.
154 * drop the trailing zero bytes refer to ISO/IEC14496-15.
155 */
156 5 high_nibble = rbsp_buf[7] >> 4;
157 5 snprintf(constraints, sizeof(constraints),
158 high_nibble ? "%02x.%x" : "%02x",
159
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 rbsp_buf[6], high_nibble);
160 /* skip 8 + 8 + 32 + 4 + 43 + 1 bit */
161 5 level = rbsp_buf[12];
162 5 av_freep(&rbsp_buf);
163 5 break;
164 }
165 2206 data++;
166 }
167
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
22 if (par->codec_tag == MKTAG('h','v','c','1') &&
168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 profile != AV_PROFILE_UNKNOWN &&
169 profile_compatibility != AV_PROFILE_UNKNOWN &&
170 tier != 0 &&
171 level != AV_LEVEL_UNKNOWN &&
172 constraints[0] != '\0') {
173 av_bprintf(out, "%s.%d.%x.%c%d.%s",
174 av_fourcc2str(par->codec_tag), profile,
175 profile_compatibility, tier, level, constraints);
176 } else
177 22 return AVERROR(EINVAL);
178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 182 times.
182 } else if (par->codec_id == AV_CODEC_ID_LCEVC) {
179 LCEVCDecoderConfigurationRecord lvcc;
180 int err;
181 if (!par->extradata_size)
182 return AVERROR(EINVAL);
183 if ((err = ff_lcvec_parse_config_record(&lvcc, par->extradata, par->extradata_size)) < 0)
184 return err;
185 av_bprintf(out, "lvc1.vprf%u.vlev%u", lvcc.profile_idc, lvcc.level_idc);
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 182 times.
182 } else if (par->codec_id == AV_CODEC_ID_AV1) {
187 // https://aomediacodec.github.io/av1-isobmff/#codecsparam
188 AV1SequenceParameters seq;
189 int err;
190 if (!par->extradata_size)
191 return AVERROR(EINVAL);
192 if ((err = ff_av1_parse_seq_header(&seq, par->extradata, par->extradata_size)) < 0)
193 return err;
194
195 av_bprintf(out, "av01.%01u.%02u%s.%02u",
196 seq.profile, seq.level, seq.tier ? "H" : "M", seq.bitdepth);
197 if (seq.color_description_present_flag)
198 av_bprintf(out, ".%01u.%01u%01u%01u.%02u.%02u.%02u.%01u",
199 seq.monochrome,
200 seq.chroma_subsampling_x, seq.chroma_subsampling_y, seq.chroma_sample_position,
201 seq.color_primaries, seq.transfer_characteristics, seq.matrix_coefficients,
202 seq.color_range);
203
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 180 times.
182 } else if (par->codec_id == AV_CODEC_ID_MPEG4) {
204 // RFC 6381
205 2 av_bprintf(out, "mp4v.20");
206 // Unimplemented, should output ProfileLevelIndication as a decimal number
207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (logctx)
208 av_log(logctx, AV_LOG_WARNING, "Incomplete RFC 6381 codec string for mp4v\n");
209
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 169 times.
180 } else if (par->codec_id == AV_CODEC_ID_MP2) {
210 11 av_bprintf(out, "mp4a.40.33");
211
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 167 times.
169 } else if (par->codec_id == AV_CODEC_ID_MP3) {
212 2 av_bprintf(out, "mp4a.40.34");
213
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 149 times.
167 } else if (par->codec_id == AV_CODEC_ID_AAC) {
214 // RFC 6381
215 18 int aot = 2;
216
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (par->extradata_size >= 2) {
217 18 aot = par->extradata[0] >> 3;
218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (aot == 31)
219 aot = ((AV_RB16(par->extradata) >> 5) & 0x3f) + 32;
220 } else if (par->profile != AV_PROFILE_UNKNOWN)
221 aot = par->profile + 1;
222 18 av_bprintf(out, "mp4a.40.%d", aot);
223
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 134 times.
149 } else if (par->codec_id == AV_CODEC_ID_AC3) {
224 15 av_bprintf(out, "ac-3");
225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 134 times.
134 } else if (par->codec_id == AV_CODEC_ID_EAC3) {
226 av_bprintf(out, "ec-3");
227 } else {
228 134 return AVERROR(EINVAL);
229 }
230 67 return 0;
231 }
232
233 379 int av_mime_codec_str(const AVCodecParameters *par,
234 AVRational frame_rate, struct AVBPrint *out)
235 {
236 379 return ff_make_codec_str(NULL, par, &frame_rate, out);
237 }
238