| 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 |