| @@ -0,0 +1,297 @@ |
| | 1 | /* |
| | 2 | * LPCM codecs for PCM formats found in Blu-ray m2ts streams |
| | 3 | * |
| | 4 | * This file is part of FFmpeg. |
| | 5 | * |
| | 6 | * FFmpeg is free software; you can redistribute it and/or |
| | 7 | * modify it under the terms of the GNU Lesser General Public |
| | 8 | * License as published by the Free Software Foundation; either |
| | 9 | * version 2.1 of the License, or (at your option) any later version. |
| | 10 | * |
| | 11 | * FFmpeg is distributed in the hope that it will be useful, |
| | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | 14 | * Lesser General Public License for more details. |
| | 15 | * |
| | 16 | * You should have received a copy of the GNU Lesser General Public |
| | 17 | * License along with FFmpeg; if not, write to the Free Software |
| | 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| | 19 | */ |
| | 20 | |
| | 21 | #include "libavutil/channel_layout.h" |
| | 22 | #include "avcodec.h" |
| | 23 | #include "bytestream.h" |
| | 24 | #include "encode.h" |
| | 25 | #include "internal.h" |
| | 26 | |
| | 27 | typedef struct BlurayPCMEncContext { |
| | 28 | uint16_t header; // Header added to every frame |
| | 29 | } BlurayPCMEncContext; |
| | 30 | |
| | 31 | static av_cold int pcm_bluray_encode_init(AVCodecContext *avctx) |
| | 32 | { |
| | 33 | BlurayPCMEncContext *s = avctx->priv_data; |
| | 34 | uint8_t ch_layout; |
| | 35 | int quant, freq; |
| | 36 | |
| | 37 | switch (avctx->sample_rate) { |
| | 38 | case 48000: |
| | 39 | freq = 1; |
| | 40 | break; |
| | 41 | case 96000: |
| | 42 | freq = 4; |
| | 43 | break; |
| | 44 | case 192000: |
| | 45 | freq = 5; |
| | 46 | break; |
| | 47 | default: |
| | 48 | return AVERROR_BUG; |
| | 49 | } |
| | 50 | |
| | 51 | switch (avctx->sample_fmt) { |
| | 52 | case AV_SAMPLE_FMT_S16: |
| | 53 | avctx->bits_per_coded_sample = 16; |
| | 54 | quant = 1; |
| | 55 | break; |
| | 56 | case AV_SAMPLE_FMT_S32: |
| | 57 | avctx->bits_per_coded_sample = 24; |
| | 58 | quant = 3; |
| | 59 | break; |
| | 60 | default: |
| | 61 | return AVERROR_BUG; |
| | 62 | } |
| | 63 | |
| | 64 | switch (avctx->channel_layout) { |
| | 65 | case AV_CH_LAYOUT_MONO: |
| | 66 | ch_layout = 1; |
| | 67 | break; |
| | 68 | case AV_CH_LAYOUT_STEREO: |
| | 69 | ch_layout = 3; |
| | 70 | break; |
| | 71 | case AV_CH_LAYOUT_SURROUND: |
| | 72 | ch_layout = 4; |
| | 73 | break; |
| | 74 | case AV_CH_LAYOUT_2_1: |
| | 75 | ch_layout = 5; |
| | 76 | break; |
| | 77 | case AV_CH_LAYOUT_4POINT0: |
| | 78 | ch_layout = 6; |
| | 79 | break; |
| | 80 | case AV_CH_LAYOUT_2_2: |
| | 81 | ch_layout = 7; |
| | 82 | break; |
| | 83 | case AV_CH_LAYOUT_5POINT0: |
| | 84 | ch_layout = 8; |
| | 85 | break; |
| | 86 | case AV_CH_LAYOUT_5POINT1: |
| | 87 | ch_layout = 9; |
| | 88 | break; |
| | 89 | case AV_CH_LAYOUT_7POINT0: |
| | 90 | ch_layout = 10; |
| | 91 | break; |
| | 92 | case AV_CH_LAYOUT_7POINT1: |
| | 93 | ch_layout = 11; |
| | 94 | break; |
| | 95 | default: |
| | 96 | return AVERROR_BUG; |
| | 97 | } |
| | 98 | |
| | 99 | s->header = (((ch_layout << 4) | freq) << 8) | (quant << 6); |
| | 100 | |
| | 101 | return 0; |
| | 102 | } |
| | 103 | |
| | 104 | static int pcm_bluray_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, |
| | 105 | const AVFrame *frame, int *got_packet_ptr) |
| | 106 | { |
| | 107 | BlurayPCMEncContext *s = avctx->priv_data; |
| | 108 | int sample_size, samples, channel, num_dest_channels; |
| | 109 | const int16_t *src16; |
| | 110 | const int32_t *src32; |
| | 111 | unsigned pkt_size; |
| | 112 | PutByteContext pb; |
| | 113 | int ret; |
| | 114 | |
| | 115 | num_dest_channels = FFALIGN(avctx->channels, 2); |
| | 116 | sample_size = (num_dest_channels * |
| | 117 | (avctx->sample_fmt == AV_SAMPLE_FMT_S16 ? 16 : 24)) >> 3; |
| | 118 | samples = frame->nb_samples; |
| | 119 | |
| | 120 | pkt_size = sample_size * samples + 4; |
| | 121 | |
| | 122 | if ((ret = ff_get_encode_buffer(avctx, avpkt, pkt_size, 0)) < 0) |
| | 123 | return ret; |
| | 124 | |
| | 125 | AV_WB16(avpkt->data, pkt_size - 4); |
| | 126 | AV_WB16(avpkt->data + 2, s->header); |
| | 127 | |
| | 128 | src16 = (const int16_t *)frame->data[0]; |
| | 129 | src32 = (const int32_t *)frame->data[0]; |
| | 130 | |
| | 131 | bytestream2_init_writer(&pb, avpkt->data + 4, avpkt->size - 4); |
| | 132 | |
| | 133 | switch (avctx->channel_layout) { |
| | 134 | /* cases with same number of source and coded channels */ |
| | 135 | case AV_CH_LAYOUT_STEREO: |
| | 136 | case AV_CH_LAYOUT_4POINT0: |
| | 137 | case AV_CH_LAYOUT_2_2: |
| | 138 | samples *= num_dest_channels; |
| | 139 | if (AV_SAMPLE_FMT_S16 == avctx->sample_fmt) { |
| | 140 | #if HAVE_BIGENDIAN |
| | 141 | bytestream2_put_bufferu(&pb, frame->data[0], samples * 2); |
| | 142 | #else |
| | 143 | do { |
| | 144 | bytestream2_put_be16u(&pb, *src16++); |
| | 145 | } while (--samples); |
| | 146 | #endif |
| | 147 | } else { |
| | 148 | do { |
| | 149 | bytestream2_put_be24u(&pb, (*src32++) >> 8); |
| | 150 | } while (--samples); |
| | 151 | } |
| | 152 | break; |
| | 153 | /* cases where number of source channels = coded channels + 1 */ |
| | 154 | case AV_CH_LAYOUT_MONO: |
| | 155 | case AV_CH_LAYOUT_SURROUND: |
| | 156 | case AV_CH_LAYOUT_2_1: |
| | 157 | case AV_CH_LAYOUT_5POINT0: |
| | 158 | if (AV_SAMPLE_FMT_S16 == avctx->sample_fmt) { |
| | 159 | do { |
| | 160 | #if HAVE_BIGENDIAN |
| | 161 | bytestream2_put_bufferu(&pb, (const uint8_t *)src16, avctx->channels * 2); |
| | 162 | src16 += avctx->channels; |
| | 163 | #else |
| | 164 | channel = avctx->channels; |
| | 165 | do { |
| | 166 | bytestream2_put_be16u(&pb, *src16++); |
| | 167 | } while (--channel); |
| | 168 | #endif |
| | 169 | bytestream2_put_ne16(&pb, 0); |
| | 170 | } while (--samples); |
| | 171 | } else { |
| | 172 | do { |
| | 173 | channel = avctx->channels; |
| | 174 | do { |
| | 175 | bytestream2_put_be24u(&pb, (*src32++) >> 8); |
| | 176 | } while (--channel); |
| | 177 | bytestream2_put_ne24(&pb, 0); |
| | 178 | } while (--samples); |
| | 179 | } |
| | 180 | break; |
| | 181 | /* remapping: L, R, C, LBack, RBack, LF */ |
| | 182 | case AV_CH_LAYOUT_5POINT1: |
| | 183 | if (AV_SAMPLE_FMT_S16 == avctx->sample_fmt) { |
| | 184 | do { |
| | 185 | bytestream2_put_be16u(&pb, src16[0]); |
| | 186 | bytestream2_put_be16u(&pb, src16[1]); |
| | 187 | bytestream2_put_be16u(&pb, src16[2]); |
| | 188 | bytestream2_put_be16u(&pb, src16[4]); |
| | 189 | bytestream2_put_be16u(&pb, src16[5]); |
| | 190 | bytestream2_put_be16u(&pb, src16[3]); |
| | 191 | src16 += 6; |
| | 192 | } while (--samples); |
| | 193 | } else { |
| | 194 | do { |
| | 195 | bytestream2_put_be24u(&pb, src32[0] >> 8); |
| | 196 | bytestream2_put_be24u(&pb, src32[1] >> 8); |
| | 197 | bytestream2_put_be24u(&pb, src32[2] >> 8); |
| | 198 | bytestream2_put_be24u(&pb, src32[4] >> 8); |
| | 199 | bytestream2_put_be24u(&pb, src32[5] >> 8); |
| | 200 | bytestream2_put_be24u(&pb, src32[3] >> 8); |
| | 201 | src32 += 6; |
| | 202 | } while (--samples); |
| | 203 | } |
| | 204 | break; |
| | 205 | /* remapping: L, R, C, LSide, LBack, RBack, RSide, <unused> */ |
| | 206 | case AV_CH_LAYOUT_7POINT0: |
| | 207 | if (AV_SAMPLE_FMT_S16 == avctx->sample_fmt) { |
| | 208 | do { |
| | 209 | bytestream2_put_be16u(&pb, src16[0]); |
| | 210 | bytestream2_put_be16u(&pb, src16[1]); |
| | 211 | bytestream2_put_be16u(&pb, src16[2]); |
| | 212 | bytestream2_put_be16u(&pb, src16[5]); |
| | 213 | bytestream2_put_be16u(&pb, src16[3]); |
| | 214 | bytestream2_put_be16u(&pb, src16[4]); |
| | 215 | bytestream2_put_be16u(&pb, src16[6]); |
| | 216 | src16 += 7; |
| | 217 | bytestream2_put_ne16(&pb, 0); |
| | 218 | } while (--samples); |
| | 219 | } else { |
| | 220 | do { |
| | 221 | bytestream2_put_be24u(&pb, src32[0] >> 8); |
| | 222 | bytestream2_put_be24u(&pb, src32[1] >> 8); |
| | 223 | bytestream2_put_be24u(&pb, src32[2] >> 8); |
| | 224 | bytestream2_put_be24u(&pb, src32[5] >> 8); |
| | 225 | bytestream2_put_be24u(&pb, src32[3] >> 8); |
| | 226 | bytestream2_put_be24u(&pb, src32[4] >> 8); |
| | 227 | bytestream2_put_be24u(&pb, src32[6] >> 8); |
| | 228 | src32 += 7; |
| | 229 | bytestream2_put_ne24(&pb, 0); |
| | 230 | } while (--samples); |
| | 231 | } |
| | 232 | break; |
| | 233 | /* remapping: L, R, C, LSide, LBack, RBack, RSide, LF */ |
| | 234 | case AV_CH_LAYOUT_7POINT1: |
| | 235 | if (AV_SAMPLE_FMT_S16 == avctx->sample_fmt) { |
| | 236 | do { |
| | 237 | bytestream2_put_be16u(&pb, src16[0]); |
| | 238 | bytestream2_put_be16u(&pb, src16[1]); |
| | 239 | bytestream2_put_be16u(&pb, src16[2]); |
| | 240 | bytestream2_put_be16u(&pb, src16[6]); |
| | 241 | bytestream2_put_be16u(&pb, src16[4]); |
| | 242 | bytestream2_put_be16u(&pb, src16[5]); |
| | 243 | bytestream2_put_be16u(&pb, src16[7]); |
| | 244 | bytestream2_put_be16u(&pb, src16[3]); |
| | 245 | src16 += 8; |
| | 246 | } while (--samples); |
| | 247 | } else { |
| | 248 | do { |
| | 249 | bytestream2_put_be24u(&pb, src32[0]); |
| | 250 | bytestream2_put_be24u(&pb, src32[1]); |
| | 251 | bytestream2_put_be24u(&pb, src32[2]); |
| | 252 | bytestream2_put_be24u(&pb, src32[6]); |
| | 253 | bytestream2_put_be24u(&pb, src32[4]); |
| | 254 | bytestream2_put_be24u(&pb, src32[5]); |
| | 255 | bytestream2_put_be24u(&pb, src32[7]); |
| | 256 | bytestream2_put_be24u(&pb, src32[3]); |
| | 257 | src32 += 8; |
| | 258 | } while (--samples); |
| | 259 | } |
| | 260 | break; |
| | 261 | default: |
| | 262 | return AVERROR_BUG; |
| | 263 | } |
| | 264 | |
| | 265 | avpkt->pts = frame->pts; |
| | 266 | avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples); |
| | 267 | *got_packet_ptr = 1; |
| | 268 | |
| | 269 | return 0; |
| | 270 | } |
| | 271 | |
| | 272 | const AVCodec ff_pcm_bluray_encoder = { |
| | 273 | .name = "pcm_bluray", |
| | 274 | .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16|20|24-bit big-endian for Blu-ray media"), |
| | 275 | .type = AVMEDIA_TYPE_AUDIO, |
| | 276 | .id = AV_CODEC_ID_PCM_BLURAY, |
| | 277 | .priv_data_size = sizeof(BlurayPCMEncContext), |
| | 278 | .init = pcm_bluray_encode_init, |
| | 279 | .encode2 = pcm_bluray_encode_frame, |
| | 280 | .supported_samplerates = (const int[]) { 48000, 96000, 192000, 0 }, |
| | 281 | .channel_layouts = (const uint64_t[]) { |
| | 282 | AV_CH_LAYOUT_MONO, |
| | 283 | AV_CH_LAYOUT_STEREO, |
| | 284 | AV_CH_LAYOUT_SURROUND, |
| | 285 | AV_CH_LAYOUT_2_1, |
| | 286 | AV_CH_LAYOUT_4POINT0, |
| | 287 | AV_CH_LAYOUT_2_2, |
| | 288 | AV_CH_LAYOUT_5POINT0, |
| | 289 | AV_CH_LAYOUT_5POINT1, |
| | 290 | AV_CH_LAYOUT_7POINT0, |
| | 291 | AV_CH_LAYOUT_7POINT1, |
| | 292 | 0 }, |
| | 293 | .sample_fmts = (const enum AVSampleFormat[]) { |
| | 294 | AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE }, |
| | 295 | .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, |
| | 296 | .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_VARIABLE_FRAME_SIZE, |
| | 297 | }; |