00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "libavutil/audioconvert.h"
00028 #include "avcodec.h"
00029 #include "bytestream.h"
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00052 static int pcm_bluray_parse_header(AVCodecContext *avctx,
00053 const uint8_t *header)
00054 {
00055 static const uint8_t bits_per_samples[4] = { 0, 16, 20, 24 };
00056 static const uint32_t channel_layouts[16] = {
00057 0, AV_CH_LAYOUT_MONO, 0, AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_SURROUND,
00058 AV_CH_LAYOUT_2_1, AV_CH_LAYOUT_4POINT0, AV_CH_LAYOUT_2_2, AV_CH_LAYOUT_5POINT0,
00059 AV_CH_LAYOUT_5POINT1, AV_CH_LAYOUT_7POINT0, AV_CH_LAYOUT_7POINT1, 0, 0, 0, 0
00060 };
00061 static const uint8_t channels[16] = {
00062 0, 1, 0, 2, 3, 3, 4, 4, 5, 6, 7, 8, 0, 0, 0, 0
00063 };
00064 uint8_t channel_layout = header[2] >> 4;
00065
00066 if (avctx->debug & FF_DEBUG_PICT_INFO)
00067 av_dlog(avctx, "pcm_bluray_parse_header: header = %02x%02x%02x%02x\n",
00068 header[0], header[1], header[2], header[3]);
00069
00070
00071 avctx->bits_per_coded_sample = bits_per_samples[header[3] >> 6];
00072 if (!avctx->bits_per_coded_sample) {
00073 av_log(avctx, AV_LOG_ERROR, "unsupported sample depth (0)\n");
00074 return -1;
00075 }
00076 avctx->sample_fmt = avctx->bits_per_coded_sample == 16 ? AV_SAMPLE_FMT_S16 :
00077 AV_SAMPLE_FMT_S32;
00078
00079
00080 switch (header[2] & 0x0f) {
00081 case 1:
00082 avctx->sample_rate = 48000;
00083 break;
00084 case 4:
00085 avctx->sample_rate = 96000;
00086 break;
00087 case 5:
00088 avctx->sample_rate = 192000;
00089 break;
00090 default:
00091 avctx->sample_rate = 0;
00092 av_log(avctx, AV_LOG_ERROR, "unsupported sample rate (%d)\n",
00093 header[2] & 0x0f);
00094 return -1;
00095 }
00096
00097
00098
00099
00100
00101
00102
00103 avctx->channel_layout = channel_layouts[channel_layout];
00104 avctx->channels = channels[channel_layout];
00105 if (!avctx->channels) {
00106 av_log(avctx, AV_LOG_ERROR, "unsupported channel configuration (%d)\n",
00107 channel_layout);
00108 return -1;
00109 }
00110
00111 avctx->bit_rate = avctx->channels * avctx->sample_rate *
00112 avctx->bits_per_coded_sample;
00113
00114 if (avctx->debug & FF_DEBUG_PICT_INFO)
00115 av_dlog(avctx,
00116 "pcm_bluray_parse_header: %d channels, %d bits per sample, %d kHz, %d kbit\n",
00117 avctx->channels, avctx->bits_per_coded_sample,
00118 avctx->sample_rate, avctx->bit_rate);
00119 return 0;
00120 }
00121
00122 static int pcm_bluray_decode_frame(AVCodecContext *avctx,
00123 void *data,
00124 int *data_size,
00125 AVPacket *avpkt)
00126 {
00127 const uint8_t *src = avpkt->data;
00128 int buf_size = avpkt->size;
00129 int num_source_channels, channel, retval;
00130 int sample_size, samples, output_size;
00131 int16_t *dst16 = data;
00132 int32_t *dst32 = data;
00133
00134 if (buf_size < 4) {
00135 av_log(avctx, AV_LOG_ERROR, "PCM packet too small\n");
00136 return -1;
00137 }
00138
00139 if (pcm_bluray_parse_header(avctx, src))
00140 return -1;
00141 src += 4;
00142 buf_size -= 4;
00143
00144
00145 num_source_channels = FFALIGN(avctx->channels, 2);
00146 sample_size = (num_source_channels * avctx->bits_per_coded_sample) >> 3;
00147 samples = buf_size / sample_size;
00148
00149 output_size = samples * avctx->channels *
00150 (avctx->sample_fmt == AV_SAMPLE_FMT_S32 ? 4 : 2);
00151 if (output_size > *data_size) {
00152 av_log(avctx, AV_LOG_ERROR,
00153 "Insufficient output buffer space (%d bytes, needed %d bytes)\n",
00154 *data_size, output_size);
00155 return -1;
00156 }
00157 *data_size = output_size;
00158
00159 if (samples) {
00160 switch (avctx->channel_layout) {
00161
00162 case AV_CH_LAYOUT_STEREO:
00163 case AV_CH_LAYOUT_4POINT0:
00164 case AV_CH_LAYOUT_2_2:
00165 samples *= num_source_channels;
00166 if (AV_SAMPLE_FMT_S16 == avctx->sample_fmt) {
00167 #if HAVE_BIGENDIAN
00168 memcpy(dst16, src, output_size);
00169 #else
00170 do {
00171 *dst16++ = bytestream_get_be16(&src);
00172 } while (--samples);
00173 #endif
00174 } else {
00175 do {
00176 *dst32++ = bytestream_get_be24(&src) << 8;
00177 } while (--samples);
00178 }
00179 break;
00180
00181 case AV_CH_LAYOUT_MONO:
00182 case AV_CH_LAYOUT_SURROUND:
00183 case AV_CH_LAYOUT_2_1:
00184 case AV_CH_LAYOUT_5POINT0:
00185 if (AV_SAMPLE_FMT_S16 == avctx->sample_fmt) {
00186 do {
00187 #if HAVE_BIGENDIAN
00188 memcpy(dst16, src, avctx->channels * 2);
00189 dst16 += avctx->channels;
00190 src += sample_size;
00191 #else
00192 channel = avctx->channels;
00193 do {
00194 *dst16++ = bytestream_get_be16(&src);
00195 } while (--channel);
00196 src += 2;
00197 #endif
00198 } while (--samples);
00199 } else {
00200 do {
00201 channel = avctx->channels;
00202 do {
00203 *dst32++ = bytestream_get_be24(&src) << 8;
00204 } while (--channel);
00205 src += 3;
00206 } while (--samples);
00207 }
00208 break;
00209
00210 case AV_CH_LAYOUT_5POINT1:
00211 if (AV_SAMPLE_FMT_S16 == avctx->sample_fmt) {
00212 do {
00213 dst16[0] = bytestream_get_be16(&src);
00214 dst16[1] = bytestream_get_be16(&src);
00215 dst16[2] = bytestream_get_be16(&src);
00216 dst16[4] = bytestream_get_be16(&src);
00217 dst16[5] = bytestream_get_be16(&src);
00218 dst16[3] = bytestream_get_be16(&src);
00219 dst16 += 6;
00220 } while (--samples);
00221 } else {
00222 do {
00223 dst32[0] = bytestream_get_be24(&src) << 8;
00224 dst32[1] = bytestream_get_be24(&src) << 8;
00225 dst32[2] = bytestream_get_be24(&src) << 8;
00226 dst32[4] = bytestream_get_be24(&src) << 8;
00227 dst32[5] = bytestream_get_be24(&src) << 8;
00228 dst32[3] = bytestream_get_be24(&src) << 8;
00229 dst32 += 6;
00230 } while (--samples);
00231 }
00232 break;
00233
00234 case AV_CH_LAYOUT_7POINT0:
00235 if (AV_SAMPLE_FMT_S16 == avctx->sample_fmt) {
00236 do {
00237 dst16[0] = bytestream_get_be16(&src);
00238 dst16[1] = bytestream_get_be16(&src);
00239 dst16[2] = bytestream_get_be16(&src);
00240 dst16[5] = bytestream_get_be16(&src);
00241 dst16[3] = bytestream_get_be16(&src);
00242 dst16[4] = bytestream_get_be16(&src);
00243 dst16[6] = bytestream_get_be16(&src);
00244 dst16 += 7;
00245 src += 2;
00246 } while (--samples);
00247 } else {
00248 do {
00249 dst32[0] = bytestream_get_be24(&src) << 8;
00250 dst32[1] = bytestream_get_be24(&src) << 8;
00251 dst32[2] = bytestream_get_be24(&src) << 8;
00252 dst32[5] = bytestream_get_be24(&src) << 8;
00253 dst32[3] = bytestream_get_be24(&src) << 8;
00254 dst32[4] = bytestream_get_be24(&src) << 8;
00255 dst32[6] = bytestream_get_be24(&src) << 8;
00256 dst32 += 7;
00257 src += 3;
00258 } while (--samples);
00259 }
00260 break;
00261
00262 case AV_CH_LAYOUT_7POINT1:
00263 if (AV_SAMPLE_FMT_S16 == avctx->sample_fmt) {
00264 do {
00265 dst16[0] = bytestream_get_be16(&src);
00266 dst16[1] = bytestream_get_be16(&src);
00267 dst16[2] = bytestream_get_be16(&src);
00268 dst16[6] = bytestream_get_be16(&src);
00269 dst16[4] = bytestream_get_be16(&src);
00270 dst16[5] = bytestream_get_be16(&src);
00271 dst16[7] = bytestream_get_be16(&src);
00272 dst16[3] = bytestream_get_be16(&src);
00273 dst16 += 8;
00274 } while (--samples);
00275 } else {
00276 do {
00277 dst32[0] = bytestream_get_be24(&src) << 8;
00278 dst32[1] = bytestream_get_be24(&src) << 8;
00279 dst32[2] = bytestream_get_be24(&src) << 8;
00280 dst32[6] = bytestream_get_be24(&src) << 8;
00281 dst32[4] = bytestream_get_be24(&src) << 8;
00282 dst32[5] = bytestream_get_be24(&src) << 8;
00283 dst32[7] = bytestream_get_be24(&src) << 8;
00284 dst32[3] = bytestream_get_be24(&src) << 8;
00285 dst32 += 8;
00286 } while (--samples);
00287 }
00288 break;
00289 }
00290 }
00291
00292 retval = src - avpkt->data;
00293 if (avctx->debug & FF_DEBUG_BITSTREAM)
00294 av_dlog(avctx, "pcm_bluray_decode_frame: decoded %d -> %d bytes\n",
00295 retval, *data_size);
00296 return retval;
00297 }
00298
00299 AVCodec ff_pcm_bluray_decoder = {
00300 "pcm_bluray",
00301 AVMEDIA_TYPE_AUDIO,
00302 CODEC_ID_PCM_BLURAY,
00303 0,
00304 NULL,
00305 NULL,
00306 NULL,
00307 pcm_bluray_decode_frame,
00308 .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32,
00309 AV_SAMPLE_FMT_NONE},
00310 .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16|20|24-bit big-endian for Blu-ray media"),
00311 };