| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2016 Google Inc. | ||
| 3 | * Copyright (c) 2016 KongQun Yang (kqyang@google.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 "libavutil/pixdesc.h" | ||
| 23 | #include "libavutil/pixfmt.h" | ||
| 24 | #include "libavcodec/defs.h" | ||
| 25 | #include "libavcodec/get_bits.h" | ||
| 26 | #include "vpcc.h" | ||
| 27 | |||
| 28 | #define VP9_SYNCCODE 0x498342 | ||
| 29 | |||
| 30 | enum VPX_CHROMA_SUBSAMPLING | ||
| 31 | { | ||
| 32 | VPX_SUBSAMPLING_420_VERTICAL = 0, | ||
| 33 | VPX_SUBSAMPLING_420_COLLOCATED_WITH_LUMA = 1, | ||
| 34 | VPX_SUBSAMPLING_422 = 2, | ||
| 35 | VPX_SUBSAMPLING_444 = 3, | ||
| 36 | }; | ||
| 37 | |||
| 38 | 2 | static int get_vpx_chroma_subsampling(void *logctx, | |
| 39 | enum AVPixelFormat pixel_format, | ||
| 40 | enum AVChromaLocation chroma_location) | ||
| 41 | { | ||
| 42 | int chroma_w, chroma_h; | ||
| 43 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (av_pix_fmt_get_chroma_sub_sample(pixel_format, &chroma_w, &chroma_h) == 0) { |
| 44 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | if (chroma_w == 1 && chroma_h == 1) { |
| 45 | return (chroma_location == AVCHROMA_LOC_LEFT) | ||
| 46 | ? VPX_SUBSAMPLING_420_VERTICAL | ||
| 47 | 2 | : VPX_SUBSAMPLING_420_COLLOCATED_WITH_LUMA; | |
| 48 | ✗ | } else if (chroma_w == 1 && chroma_h == 0) { | |
| 49 | ✗ | return VPX_SUBSAMPLING_422; | |
| 50 | ✗ | } else if (chroma_w == 0 && chroma_h == 0) { | |
| 51 | ✗ | return VPX_SUBSAMPLING_444; | |
| 52 | } | ||
| 53 | } | ||
| 54 | ✗ | if (logctx) | |
| 55 | ✗ | av_log(logctx, AV_LOG_ERROR, "Unsupported pixel format (%d)\n", pixel_format); | |
| 56 | ✗ | return -1; | |
| 57 | } | ||
| 58 | |||
| 59 | 2 | static int get_bit_depth(void *logctx, enum AVPixelFormat pixel_format) | |
| 60 | { | ||
| 61 | 2 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pixel_format); | |
| 62 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (desc == NULL) { |
| 63 | ✗ | if (logctx) | |
| 64 | ✗ | av_log(logctx, AV_LOG_ERROR, "Unsupported pixel format (%d)\n", | |
| 65 | pixel_format); | ||
| 66 | ✗ | return -1; | |
| 67 | } | ||
| 68 | 2 | return desc->comp[0].depth; | |
| 69 | } | ||
| 70 | |||
| 71 | 2 | static int get_vpx_video_full_range_flag(enum AVColorRange color_range) | |
| 72 | { | ||
| 73 | 2 | return color_range == AVCOL_RANGE_JPEG; | |
| 74 | } | ||
| 75 | |||
| 76 | // Find approximate VP9 level based on the Luma's Sample rate and Picture size. | ||
| 77 | 2 | static int get_vp9_level(const AVCodecParameters *par, | |
| 78 | const AVRational *frame_rate) | ||
| 79 | { | ||
| 80 | 2 | int picture_size = par->width * par->height; | |
| 81 | int64_t sample_rate; | ||
| 82 | |||
| 83 | // All decisions will be based on picture_size, if frame rate is missing/invalid | ||
| 84 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | if (!frame_rate || !frame_rate->den) |
| 85 | 2 | sample_rate = 0; | |
| 86 | else | ||
| 87 | ✗ | sample_rate = ((int64_t)picture_size * frame_rate->num) / frame_rate->den; | |
| 88 | |||
| 89 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (picture_size <= 0) { |
| 90 | ✗ | return 0; | |
| 91 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | } else if (sample_rate <= 829440 && picture_size <= 36864) { |
| 92 | ✗ | return 10; | |
| 93 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | } else if (sample_rate <= 2764800 && picture_size <= 73728) { |
| 94 | ✗ | return 11; | |
| 95 |
3/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
|
2 | } else if (sample_rate <= 4608000 && picture_size <= 122880) { |
| 96 | 1 | return 20; | |
| 97 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | } else if (sample_rate <= 9216000 && picture_size <= 245760) { |
| 98 | ✗ | return 21; | |
| 99 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | } else if (sample_rate <= 20736000 && picture_size <= 552960) { |
| 100 | ✗ | return 30; | |
| 101 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | } else if (sample_rate <= 36864000 && picture_size <= 983040) { |
| 102 | ✗ | return 31; | |
| 103 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | } else if (sample_rate <= 83558400 && picture_size <= 2228224) { |
| 104 | 1 | return 40; | |
| 105 | ✗ | } else if (sample_rate <= 160432128 && picture_size <= 2228224) { | |
| 106 | ✗ | return 41; | |
| 107 | ✗ | } else if (sample_rate <= 311951360 && picture_size <= 8912896) { | |
| 108 | ✗ | return 50; | |
| 109 | ✗ | } else if (sample_rate <= 588251136 && picture_size <= 8912896) { | |
| 110 | ✗ | return 51; | |
| 111 | ✗ | } else if (sample_rate <= 1176502272 && picture_size <= 8912896) { | |
| 112 | ✗ | return 52; | |
| 113 | ✗ | } else if (sample_rate <= 1176502272 && picture_size <= 35651584) { | |
| 114 | ✗ | return 60; | |
| 115 | ✗ | } else if (sample_rate <= 2353004544 && picture_size <= 35651584) { | |
| 116 | ✗ | return 61; | |
| 117 | ✗ | } else if (sample_rate <= 4706009088 && picture_size <= 35651584) { | |
| 118 | ✗ | return 62; | |
| 119 | } else { | ||
| 120 | ✗ | return 0; | |
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | ✗ | static void parse_bitstream(GetBitContext *gb, int *profile, int *bit_depth) { | |
| 125 | int keyframe, invisible; | ||
| 126 | |||
| 127 | ✗ | if (get_bits(gb, 2) != 0x2) // frame marker | |
| 128 | ✗ | return; | |
| 129 | ✗ | *profile = get_bits1(gb); | |
| 130 | ✗ | *profile |= get_bits1(gb) << 1; | |
| 131 | ✗ | if (*profile == 3) | |
| 132 | ✗ | *profile += get_bits1(gb); | |
| 133 | |||
| 134 | ✗ | if (get_bits1(gb)) | |
| 135 | ✗ | return; | |
| 136 | |||
| 137 | ✗ | keyframe = !get_bits1(gb); | |
| 138 | ✗ | invisible = !get_bits1(gb); | |
| 139 | ✗ | get_bits1(gb); | |
| 140 | |||
| 141 | ✗ | if (keyframe) { | |
| 142 | ✗ | if (get_bits(gb, 24) != VP9_SYNCCODE) | |
| 143 | ✗ | return; | |
| 144 | } else { | ||
| 145 | ✗ | int intraonly = invisible ? get_bits1(gb) : 0; | |
| 146 | ✗ | if (!intraonly || get_bits(gb, 24) != VP9_SYNCCODE) | |
| 147 | ✗ | return; | |
| 148 | ✗ | if (*profile < 1) { | |
| 149 | ✗ | *bit_depth = 8; | |
| 150 | ✗ | return; | |
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | ✗ | *bit_depth = *profile <= 1 ? 8 : 10 + get_bits1(gb) * 2; | |
| 155 | } | ||
| 156 | |||
| 157 | 2 | int ff_isom_get_vpcc_features(void *logctx, const AVCodecParameters *par, | |
| 158 | const uint8_t *data, int len, | ||
| 159 | const AVRational *frame_rate, VPCC *vpcc) | ||
| 160 | { | ||
| 161 | 2 | int profile = par->profile; | |
| 162 | 4 | int level = par->level == AV_LEVEL_UNKNOWN ? | |
| 163 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | get_vp9_level(par, frame_rate) : par->level; |
| 164 | 2 | int bit_depth = get_bit_depth(logctx, par->format); | |
| 165 | int vpx_chroma_subsampling = | ||
| 166 | 2 | get_vpx_chroma_subsampling(logctx, par->format, par->chroma_location); | |
| 167 | int vpx_video_full_range_flag = | ||
| 168 | 2 | get_vpx_video_full_range_flag(par->color_range); | |
| 169 | |||
| 170 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (bit_depth < 0 || vpx_chroma_subsampling < 0) |
| 171 | ✗ | return AVERROR_INVALIDDATA; | |
| 172 | |||
| 173 |
4/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
2 | if (len && (profile == AV_PROFILE_UNKNOWN || !bit_depth)) { |
| 174 | GetBitContext gb; | ||
| 175 | |||
| 176 | ✗ | int ret = init_get_bits8(&gb, data, len); | |
| 177 | ✗ | if (ret < 0) | |
| 178 | ✗ | return ret; | |
| 179 | |||
| 180 | ✗ | parse_bitstream(&gb, &profile, &bit_depth); | |
| 181 | } | ||
| 182 | |||
| 183 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | if (profile == AV_PROFILE_UNKNOWN && bit_depth) { |
| 184 | ✗ | if (vpx_chroma_subsampling == VPX_SUBSAMPLING_420_VERTICAL || | |
| 185 | vpx_chroma_subsampling == VPX_SUBSAMPLING_420_COLLOCATED_WITH_LUMA) { | ||
| 186 | ✗ | profile = (bit_depth == 8) ? AV_PROFILE_VP9_0 : AV_PROFILE_VP9_2; | |
| 187 | } else { | ||
| 188 | ✗ | profile = (bit_depth == 8) ? AV_PROFILE_VP9_1 : AV_PROFILE_VP9_3; | |
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 |
2/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
2 | if ((profile == AV_PROFILE_UNKNOWN || !bit_depth) && logctx) |
| 193 | ✗ | av_log(logctx, AV_LOG_WARNING, "VP9 profile and/or bit depth not set or could not be derived\n"); | |
| 194 | |||
| 195 | 2 | vpcc->profile = profile; | |
| 196 | 2 | vpcc->level = level; | |
| 197 | 2 | vpcc->bitdepth = bit_depth; | |
| 198 | 2 | vpcc->chroma_subsampling = vpx_chroma_subsampling; | |
| 199 | 2 | vpcc->full_range_flag = vpx_video_full_range_flag; | |
| 200 | |||
| 201 | 2 | return 0; | |
| 202 | } | ||
| 203 | |||
| 204 | 2 | int ff_isom_write_vpcc(void *logctx, AVIOContext *pb, | |
| 205 | const uint8_t *data, int len, | ||
| 206 | const AVCodecParameters *par) | ||
| 207 | { | ||
| 208 | VPCC vpcc; | ||
| 209 | int ret; | ||
| 210 | |||
| 211 | 2 | ret = ff_isom_get_vpcc_features(logctx, par, data, len, NULL, &vpcc); | |
| 212 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) |
| 213 | ✗ | return ret; | |
| 214 | |||
| 215 | 2 | avio_w8(pb, 1); /* version */ | |
| 216 | 2 | avio_wb24(pb, 0); /* flags */ | |
| 217 | 2 | avio_w8(pb, vpcc.profile); | |
| 218 | 2 | avio_w8(pb, vpcc.level); | |
| 219 | 2 | avio_w8(pb, (vpcc.bitdepth << 4) | (vpcc.chroma_subsampling << 1) | vpcc.full_range_flag); | |
| 220 | 2 | avio_w8(pb, par->color_primaries); | |
| 221 | 2 | avio_w8(pb, par->color_trc); | |
| 222 | 2 | avio_w8(pb, par->color_space); | |
| 223 | |||
| 224 | // vp9 does not have codec initialization data. | ||
| 225 | 2 | avio_wb16(pb, 0); | |
| 226 | 2 | return 0; | |
| 227 | } | ||
| 228 |