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