| 1 | /* |
| 2 | Copyright (c) 2012, Broadcom Europe Ltd |
| 3 | All rights reserved. |
| 4 | |
| 5 | Redistribution and use in source and binary forms, with or without |
| 6 | modification, are permitted provided that the following conditions are met: |
| 7 | * Redistributions of source code must retain the above copyright |
| 8 | notice, this list of conditions and the following disclaimer. |
| 9 | * Redistributions in binary form must reproduce the above copyright |
| 10 | notice, this list of conditions and the following disclaimer in the |
| 11 | documentation and/or other materials provided with the distribution. |
| 12 | * Neither the name of the copyright holder nor the |
| 13 | names of its contributors may be used to endorse or promote products |
| 14 | derived from this software without specific prior written permission. |
| 15 | |
| 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
| 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | */ |
| 27 | #include <stdlib.h> |
| 28 | #include <string.h> |
| 29 | |
| 30 | #define CONTAINER_IS_BIG_ENDIAN |
| 31 | //#define ENABLE_CONTAINERS_LOG_FORMAT |
| 32 | //#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE |
| 33 | #define CONTAINER_HELPER_LOG_INDENT(a) 0 |
| 34 | #include "containers/core/containers_private.h" |
| 35 | #include "containers/core/containers_io_helpers.h" |
| 36 | #include "containers/core/containers_utils.h" |
| 37 | #include "containers/core/containers_logging.h" |
| 38 | #include "mpga_common.h" |
| 39 | |
| 40 | /****************************************************************************** |
| 41 | Defines and constants. |
| 42 | ******************************************************************************/ |
| 43 | #define MPGA_XING_HAS_FRAMES 0x00000001 |
| 44 | #define MPGA_XING_HAS_BYTES 0x00000002 |
| 45 | #define MPGA_XING_HAS_TOC 0x00000004 |
| 46 | #define MPGA_XING_HAS_QUALITY 0x00000008 |
| 47 | |
| 48 | #define MPGA_MAX_BAD_FRAMES 4096 /*< Maximum number of failed byte-wise syncs, |
| 49 | should be at least 2881+4 to cover the largest |
| 50 | frame size (MPEG2.5 Layer 2, 160kbit/s 8kHz) |
| 51 | + next frame header */ |
| 52 | |
| 53 | static const unsigned int mpga_sample_rate_adts[16] = |
| 54 | {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350}; |
| 55 | |
| 56 | static const GUID_T = |
| 57 | {0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}}; |
| 58 | |
| 59 | /****************************************************************************** |
| 60 | Type definitions |
| 61 | ******************************************************************************/ |
| 62 | typedef struct VC_CONTAINER_MODULE_T |
| 63 | { |
| 64 | VC_CONTAINER_TRACK_T *track; |
| 65 | uint64_t data_offset; |
| 66 | uint64_t data_size; |
| 67 | uint64_t num_frames; /**< Total number of frames (if known) */ |
| 68 | unsigned int frame_size_samples; /**< Frame size in samples */ |
| 69 | unsigned int bitrate; /**< Bitrate (might change on a per-frame basis if VBR) */ |
| 70 | unsigned int sample_rate; |
| 71 | unsigned int channels; |
| 72 | |
| 73 | /* MPEG audio header information */ |
| 74 | unsigned int version; /**< 1 for MPEG1, 2 for MPEG2, etc. */ |
| 75 | unsigned int layer; |
| 76 | |
| 77 | /* VBR header information */ |
| 78 | uint8_t xing_toc[100]; |
| 79 | int xing_toc_valid; |
| 80 | |
| 81 | /* Per-frame state (updated upon a read or a seek) */ |
| 82 | unsigned int frame_size; |
| 83 | unsigned int frame_data_left; |
| 84 | uint64_t frame_index; |
| 85 | int64_t frame_offset; |
| 86 | int64_t frame_time_pos; /**< pts of current frame */ |
| 87 | unsigned int frame_bitrate; /**< bitrate of current frame */ |
| 88 | |
| 89 | VC_CONTAINER_STATUS_T (*)( uint8_t [MPGA_HEADER_SIZE], |
| 90 | uint32_t *p_frame_size, unsigned int *p_frame_bitrate, unsigned int *p_version, |
| 91 | unsigned int *p_layer, unsigned int *p_sample_rate, unsigned int *p_channels, |
| 92 | unsigned int *p_frame_size_samples, unsigned int *p_offset); |
| 93 | |
| 94 | uint8_t [2]; /**< codec extra data for aac */ |
| 95 | |
| 96 | } VC_CONTAINER_MODULE_T; |
| 97 | |
| 98 | /****************************************************************************** |
| 99 | Function prototypes |
| 100 | ******************************************************************************/ |
| 101 | VC_CONTAINER_STATUS_T mpga_reader_open( VC_CONTAINER_T * ); |
| 102 | |
| 103 | /****************************************************************************** |
| 104 | Local Functions |
| 105 | ******************************************************************************/ |
| 106 | static uint32_t PEEK_BYTES_AT( VC_CONTAINER_T *p_ctx, int64_t offset, uint8_t *buffer, int size ) |
| 107 | { |
| 108 | int ret; |
| 109 | int64_t current_position = STREAM_POSITION(p_ctx); |
| 110 | SEEK(p_ctx, current_position + offset); |
| 111 | ret = PEEK_BYTES(p_ctx, buffer, size); |
| 112 | SEEK(p_ctx, current_position); |
| 113 | return ret; |
| 114 | } |
| 115 | |
| 116 | /*****************************************************************************/ |
| 117 | static VC_CONTAINER_STATUS_T ( VC_CONTAINER_T *p_ctx, |
| 118 | VC_CONTAINER_MODULE_T *module, uint8_t [MPGA_HEADER_SIZE] ) |
| 119 | { |
| 120 | VC_CONTAINER_PARAM_UNUSED(p_ctx); |
| 121 | return module->pf_parse_header(frame_header, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
| 122 | } |
| 123 | |
| 124 | /*****************************************************************************/ |
| 125 | static VC_CONTAINER_STATUS_T mpga_sync( VC_CONTAINER_T *p_ctx ) |
| 126 | { |
| 127 | VC_CONTAINER_MODULE_T *module = p_ctx->priv->module; |
| 128 | VC_CONTAINER_STATUS_T status; |
| 129 | uint8_t [MPGA_HEADER_SIZE]; |
| 130 | uint32_t frame_size; |
| 131 | unsigned int frame_bitrate, version, layer, sample_rate, channels; |
| 132 | unsigned int frame_size_samples, offset; |
| 133 | int sync_count = 0; |
| 134 | |
| 135 | /* If we can't see a full frame header, we treat this as EOS although it |
| 136 | could be a bad stream as well, the caller should distinct between |
| 137 | these two cases */ |
| 138 | if (PEEK_BYTES(p_ctx, (uint8_t*)frame_header, MPGA_HEADER_SIZE) != MPGA_HEADER_SIZE) |
| 139 | return VC_CONTAINER_ERROR_EOS; |
| 140 | |
| 141 | while (sync_count++ < MPGA_MAX_BAD_FRAMES) |
| 142 | { |
| 143 | status = module->pf_parse_header(frame_header, &frame_size, &frame_bitrate, |
| 144 | &version, &layer, &sample_rate, &channels, |
| 145 | &frame_size_samples, &offset); |
| 146 | if (status == VC_CONTAINER_SUCCESS && |
| 147 | frame_size /* We do not support free format streams */) |
| 148 | { |
| 149 | LOG_DEBUG(p_ctx, "MPEGv%d, layer %d, %d bps, %d Hz" , |
| 150 | version, layer, frame_bitrate, sample_rate); |
| 151 | if (PEEK_BYTES_AT(p_ctx, (int64_t)frame_size, frame_header, MPGA_HEADER_SIZE) != MPGA_HEADER_SIZE || |
| 152 | mpga_check_frame_header(p_ctx, module, frame_header) == VC_CONTAINER_SUCCESS) |
| 153 | break; |
| 154 | |
| 155 | /* If we've reached an ID3 tag then the frame is valid as well */ |
| 156 | if((frame_header[0] == 'I' && frame_header[1] == 'D' && frame_header[2] == '3') || |
| 157 | (frame_header[0] == 'T' && frame_header[1] == 'A' && frame_header[2] == 'G')) |
| 158 | break; |
| 159 | } |
| 160 | else if (status == VC_CONTAINER_SUCCESS) |
| 161 | { |
| 162 | LOG_DEBUG(p_ctx, "free format not supported" ); |
| 163 | } |
| 164 | |
| 165 | if (SKIP_BYTES(p_ctx, 1) != 1 || PEEK_BYTES(p_ctx, (uint8_t*)frame_header, MPGA_HEADER_SIZE) != MPGA_HEADER_SIZE) |
| 166 | return VC_CONTAINER_ERROR_EOS; |
| 167 | } |
| 168 | |
| 169 | if(sync_count > MPGA_MAX_BAD_FRAMES) /* We didn't find a valid frame */ |
| 170 | return VC_CONTAINER_ERROR_FORMAT_INVALID; |
| 171 | |
| 172 | if (module->version) |
| 173 | { |
| 174 | /* FIXME: we don't currently care whether or not the number of channels changes mid-stream */ |
| 175 | if (version != module->version || layer != module->layer) |
| 176 | { |
| 177 | LOG_DEBUG(p_ctx, "version or layer not allowed to change mid-stream" ); |
| 178 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
| 179 | } |
| 180 | } |
| 181 | else |
| 182 | { |
| 183 | module->version = version; |
| 184 | module->layer = layer; |
| 185 | module->sample_rate = sample_rate; |
| 186 | module->channels = channels; |
| 187 | module->frame_size_samples = frame_size_samples; |
| 188 | } |
| 189 | |
| 190 | if(offset) SKIP_BYTES(p_ctx, offset); |
| 191 | module->frame_data_left = module->frame_size = frame_size - offset; |
| 192 | module->frame_bitrate = frame_bitrate; |
| 193 | |
| 194 | return VC_CONTAINER_SUCCESS; |
| 195 | } |
| 196 | |
| 197 | /*****************************************************************************/ |
| 198 | static int64_t mpga_calculate_frame_time( VC_CONTAINER_T *p_ctx ) |
| 199 | { |
| 200 | VC_CONTAINER_MODULE_T *module = p_ctx->priv->module; |
| 201 | int64_t time; |
| 202 | time = INT64_C(1000000) * module->frame_index * |
| 203 | module->frame_size_samples / module->sample_rate; |
| 204 | return time; |
| 205 | } |
| 206 | |
| 207 | /*****************************************************************************/ |
| 208 | static VC_CONTAINER_STATUS_T ( VC_CONTAINER_T *p_ctx ) |
| 209 | { |
| 210 | VC_CONTAINER_MODULE_T *module = p_ctx->priv->module; |
| 211 | VC_CONTAINER_TRACK_T *track = p_ctx->tracks[0]; |
| 212 | VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_NOT_FOUND; |
| 213 | uint32_t peek_buf[1]; |
| 214 | int64_t offset, start = STREAM_POSITION(p_ctx); |
| 215 | |
| 216 | /* Look for XING header (immediately after layer 3 side information) */ |
| 217 | offset = (module->version == 1) ? ((module->channels == 1) ? INT64_C(21) : INT64_C(36)) : |
| 218 | ((module->channels == 1) ? INT64_C(13) : INT64_C(21)); |
| 219 | |
| 220 | if (PEEK_BYTES_AT(p_ctx, offset, (uint8_t*)peek_buf, 4) != 4) |
| 221 | return VC_CONTAINER_ERROR_FORMAT_INVALID; /* File would be way too small */ |
| 222 | |
| 223 | if (peek_buf[0] == VC_FOURCC('X','i','n','g') || peek_buf[0] == VC_FOURCC('I','n','f','o')) |
| 224 | { |
| 225 | uint32_t flags = 0, num_frames = 0, data_size = 0; |
| 226 | |
| 227 | /* If the first frame has a XING header then we know it's a valid (but empty) audio |
| 228 | frame so we safely parse the header whilst skipping to the next frame */ |
| 229 | SKIP_BYTES(p_ctx, offset); /* FIXME: we don't care about layer 3 side information? */ |
| 230 | |
| 231 | SKIP_FOURCC(p_ctx, "XING" ); |
| 232 | flags = READ_U32(p_ctx, "XING flags" ); |
| 233 | |
| 234 | if (flags & MPGA_XING_HAS_FRAMES) |
| 235 | num_frames = READ_U32(p_ctx, "XING frames" ); |
| 236 | |
| 237 | if (flags & MPGA_XING_HAS_BYTES) |
| 238 | data_size = READ_U32(p_ctx, "XING bytes" ); |
| 239 | |
| 240 | if (flags & MPGA_XING_HAS_TOC) |
| 241 | { |
| 242 | READ_BYTES(p_ctx, module->xing_toc, sizeof(module->xing_toc)); |
| 243 | /* TOC is useful only if we know the number of frames */ |
| 244 | if (num_frames) module->xing_toc_valid = 1; |
| 245 | /* Ensure time zero points to first frame even if TOC is broken */ |
| 246 | module->xing_toc[0] = 0; |
| 247 | } |
| 248 | |
| 249 | if (flags & MPGA_XING_HAS_QUALITY) |
| 250 | SKIP_U32(p_ctx, "XING quality" ); |
| 251 | |
| 252 | module->data_size = data_size; |
| 253 | module->num_frames = num_frames; |
| 254 | |
| 255 | if (module->num_frames && module->data_size) |
| 256 | { |
| 257 | /* We can calculate average bitrate */ |
| 258 | module->bitrate = |
| 259 | module->data_size * module->sample_rate * 8 / (module->num_frames * module->frame_size_samples); |
| 260 | } |
| 261 | |
| 262 | p_ctx->duration = (module->num_frames * module->frame_size_samples * 1000000LL) / module->sample_rate; |
| 263 | |
| 264 | /* Look for additional LAME header (follows XING) */ |
| 265 | if (PEEK_BYTES(p_ctx, (uint8_t*)peek_buf, 4) != 4) |
| 266 | return VC_CONTAINER_ERROR_FORMAT_INVALID; /* File would still be way too small */ |
| 267 | |
| 268 | if (peek_buf[0] == VC_FOURCC('L','A','M','E')) |
| 269 | { |
| 270 | uint32_t encoder_delay; |
| 271 | |
| 272 | SKIP_FOURCC(p_ctx, "LAME" ); |
| 273 | SKIP_STRING(p_ctx, 5, "LAME encoder version" ); |
| 274 | SKIP_U8(p_ctx, "LAME tag revision/VBR method" ); |
| 275 | SKIP_U8(p_ctx, "LAME LP filter value" ); |
| 276 | SKIP_U32(p_ctx, "LAME peak signal amplitude" ); |
| 277 | SKIP_U16(p_ctx, "LAME radio replay gain" ); |
| 278 | SKIP_U16(p_ctx, "LAME audiophile replay gain" ); |
| 279 | SKIP_U8(p_ctx, "LAME encoder flags" ); |
| 280 | SKIP_U8(p_ctx, "LAME ABR/minimal bitrate" ); |
| 281 | encoder_delay = READ_U24(p_ctx, "LAME encoder delay/padding" ); |
| 282 | SKIP_U8(p_ctx, "LAME misc" ); |
| 283 | SKIP_U8(p_ctx, "LAME MP3 gain" ); |
| 284 | SKIP_U16(p_ctx, "LAME presets and surround info" ); |
| 285 | SKIP_U32(p_ctx, "LAME music length" ); |
| 286 | SKIP_U16(p_ctx, "LAME music CRC" ); |
| 287 | SKIP_U16(p_ctx, "LAME tag CRC" ); |
| 288 | track->format->type->audio.gap_delay = (encoder_delay >> 12) + module->frame_size_samples; |
| 289 | track->format->type->audio.gap_padding = encoder_delay & 0xfff; |
| 290 | } |
| 291 | |
| 292 | SEEK(p_ctx, start); |
| 293 | status = VC_CONTAINER_SUCCESS; |
| 294 | } |
| 295 | |
| 296 | /* FIXME: if not success, try to read 'VBRI' header */ |
| 297 | |
| 298 | return status; |
| 299 | } |
| 300 | |
| 301 | /***************************************************************************** |
| 302 | Functions exported as part of the Container Module API |
| 303 | *****************************************************************************/ |
| 304 | static VC_CONTAINER_STATUS_T mpga_reader_read( VC_CONTAINER_T *p_ctx, |
| 305 | VC_CONTAINER_PACKET_T *p_packet, uint32_t flags ) |
| 306 | { |
| 307 | VC_CONTAINER_MODULE_T *module = p_ctx->priv->module; |
| 308 | VC_CONTAINER_TRACK_T *track = p_ctx->tracks[0]; |
| 309 | VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS; |
| 310 | |
| 311 | if (module->frame_data_left == 0) |
| 312 | { |
| 313 | status = mpga_sync(p_ctx); |
| 314 | if (status != VC_CONTAINER_SUCCESS) goto error; |
| 315 | } |
| 316 | |
| 317 | if (module->bitrate) |
| 318 | { |
| 319 | /* Simple moving average over bitrate values seen so far */ |
| 320 | module->bitrate = (module->bitrate * 31 + module->frame_bitrate) >> 5; |
| 321 | } |
| 322 | else |
| 323 | { |
| 324 | module->bitrate = module->frame_bitrate; |
| 325 | } |
| 326 | |
| 327 | /* Check if we can skip the frame straight-away */ |
| 328 | if (!track->is_enabled || |
| 329 | ((flags & VC_CONTAINER_READ_FLAG_SKIP) && !(flags & VC_CONTAINER_READ_FLAG_INFO))) |
| 330 | { |
| 331 | /* Just skip the frame */ |
| 332 | SKIP_BYTES(p_ctx, module->frame_size); |
| 333 | module->frame_data_left = 0; |
| 334 | if(!track->is_enabled) |
| 335 | status = VC_CONTAINER_ERROR_CONTINUE; |
| 336 | goto end; |
| 337 | } |
| 338 | |
| 339 | /* Fill in packet information */ |
| 340 | p_packet->flags = p_packet->track = 0; |
| 341 | if (module->frame_data_left == module->frame_size) |
| 342 | p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME; |
| 343 | else |
| 344 | p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END; |
| 345 | |
| 346 | p_packet->size = module->frame_data_left; |
| 347 | |
| 348 | p_packet->pts = module->frame_time_pos; |
| 349 | p_packet->dts = VC_CONTAINER_TIME_UNKNOWN; |
| 350 | |
| 351 | if ((flags & VC_CONTAINER_READ_FLAG_SKIP)) |
| 352 | { |
| 353 | SKIP_BYTES(p_ctx, module->frame_size); |
| 354 | module->frame_data_left = 0; |
| 355 | goto end; |
| 356 | } |
| 357 | |
| 358 | if (flags & VC_CONTAINER_READ_FLAG_INFO) |
| 359 | return VC_CONTAINER_SUCCESS; |
| 360 | |
| 361 | p_packet->size = MIN(p_packet->buffer_size, module->frame_data_left); |
| 362 | p_packet->size = READ_BYTES(p_ctx, p_packet->data, p_packet->size); |
| 363 | module->frame_data_left -= p_packet->size; |
| 364 | |
| 365 | end: |
| 366 | if (module->frame_data_left == 0) |
| 367 | { |
| 368 | module->frame_index++; |
| 369 | module->frame_offset += module->frame_size; |
| 370 | module->frame_time_pos = mpga_calculate_frame_time(p_ctx); |
| 371 | |
| 372 | #if 0 /* FIXME: is this useful e.g. progressive download? */ |
| 373 | module->num_frames = MAX(module->num_frames, module->frame_index); |
| 374 | module->data_size = MAX(module->data_size, module->frame_offset); |
| 375 | p_ctx->duration = MAX(p_ctx->duration, mpga_calculate_frame_time(p_ctx)); |
| 376 | #endif |
| 377 | } |
| 378 | |
| 379 | return status == VC_CONTAINER_SUCCESS ? STREAM_STATUS(p_ctx) : status; |
| 380 | |
| 381 | error: |
| 382 | return status; |
| 383 | } |
| 384 | |
| 385 | /*****************************************************************************/ |
| 386 | static VC_CONTAINER_STATUS_T mpga_reader_seek( VC_CONTAINER_T *p_ctx, |
| 387 | int64_t *p_offset, |
| 388 | VC_CONTAINER_SEEK_MODE_T mode, |
| 389 | VC_CONTAINER_SEEK_FLAGS_T flags) |
| 390 | { |
| 391 | VC_CONTAINER_MODULE_T *module = p_ctx->priv->module; |
| 392 | VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS; |
| 393 | uint64_t seekpos, position = STREAM_POSITION(p_ctx); |
| 394 | VC_CONTAINER_PARAM_UNUSED(flags); |
| 395 | |
| 396 | if (mode != VC_CONTAINER_SEEK_MODE_TIME || !STREAM_SEEKABLE(p_ctx)) |
| 397 | return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION; |
| 398 | |
| 399 | if (*p_offset != INT64_C(0)) |
| 400 | { |
| 401 | if (!p_ctx->duration) |
| 402 | return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION; |
| 403 | |
| 404 | if (module->xing_toc_valid) |
| 405 | { |
| 406 | int64_t ppm; |
| 407 | int percent, lower, upper, delta; |
| 408 | |
| 409 | ppm = (*p_offset * module->sample_rate) / (module->num_frames * module->frame_size_samples); |
| 410 | ppm = MIN(ppm, INT64_C(999999)); |
| 411 | |
| 412 | percent = ppm / 10000; |
| 413 | delta = ppm % 10000; |
| 414 | |
| 415 | lower = module->xing_toc[percent]; |
| 416 | upper = percent < 99 ? module->xing_toc[percent + 1] : 256; |
| 417 | |
| 418 | seekpos = module->data_offset + |
| 419 | (((module->data_size * lower) + (module->data_size * (upper - lower) * delta) / 10000) >> 8); |
| 420 | } |
| 421 | else |
| 422 | { |
| 423 | /* The following will be accurate for CBR only */ |
| 424 | seekpos = module->data_offset + (*p_offset * module->data_size) / p_ctx->duration; |
| 425 | } |
| 426 | } |
| 427 | else |
| 428 | { |
| 429 | seekpos = module->data_offset; |
| 430 | } |
| 431 | |
| 432 | SEEK(p_ctx, seekpos); |
| 433 | status = mpga_sync(p_ctx); |
| 434 | if (status && status != VC_CONTAINER_ERROR_EOS) |
| 435 | goto error; |
| 436 | |
| 437 | module->frame_index = (*p_offset * module->num_frames + (p_ctx->duration >> 1)) / p_ctx->duration; |
| 438 | module->frame_offset = STREAM_POSITION(p_ctx) - module->data_offset; |
| 439 | |
| 440 | *p_offset = module->frame_time_pos = mpga_calculate_frame_time(p_ctx); |
| 441 | |
| 442 | return STREAM_STATUS(p_ctx); |
| 443 | |
| 444 | error: |
| 445 | SEEK(p_ctx, position); |
| 446 | return status; |
| 447 | } |
| 448 | |
| 449 | /*****************************************************************************/ |
| 450 | static VC_CONTAINER_STATUS_T mpga_reader_close( VC_CONTAINER_T *p_ctx ) |
| 451 | { |
| 452 | VC_CONTAINER_MODULE_T *module = p_ctx->priv->module; |
| 453 | |
| 454 | if (p_ctx->tracks_num != 0) |
| 455 | vc_container_free_track(p_ctx, p_ctx->tracks[0]); |
| 456 | p_ctx->tracks = NULL; |
| 457 | p_ctx->tracks_num = 0; |
| 458 | free(module); |
| 459 | p_ctx->priv->module = 0; |
| 460 | return VC_CONTAINER_SUCCESS; |
| 461 | } |
| 462 | |
| 463 | /*****************************************************************************/ |
| 464 | VC_CONTAINER_STATUS_T mpga_reader_open( VC_CONTAINER_T *p_ctx ) |
| 465 | { |
| 466 | const char *extension = vc_uri_path_extension(p_ctx->priv->uri); |
| 467 | VC_CONTAINER_MODULE_T *module = 0; |
| 468 | VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS; |
| 469 | VC_CONTAINER_TRACK_T *track = NULL; |
| 470 | unsigned int i; |
| 471 | GUID_T guid; |
| 472 | |
| 473 | /* Check if the user has specified a container */ |
| 474 | vc_uri_find_query(p_ctx->priv->uri, 0, "container" , &extension); |
| 475 | |
| 476 | /* Since mpeg audio is difficult to auto-detect, we use the extension as |
| 477 | part of the autodetection */ |
| 478 | if(!extension) |
| 479 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
| 480 | if(strcasecmp(extension, "mp3" ) && strcasecmp(extension, "mp2" ) && |
| 481 | strcasecmp(extension, "aac" ) && strcasecmp(extension, "adts" )) |
| 482 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
| 483 | |
| 484 | /* Check we're not in fact dealing with an ASF file */ |
| 485 | if(PEEK_BYTES(p_ctx, (uint8_t *)&guid, sizeof(guid)) == sizeof(guid) && |
| 486 | !memcmp(&guid, &asf_guid_header, sizeof(guid))) |
| 487 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
| 488 | |
| 489 | LOG_DEBUG(p_ctx, "using mpga reader" ); |
| 490 | |
| 491 | /* Allocate our context */ |
| 492 | if ((module = malloc(sizeof(*module))) == NULL) |
| 493 | { |
| 494 | status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; |
| 495 | goto error; |
| 496 | } |
| 497 | |
| 498 | memset(module, 0, sizeof(*module)); |
| 499 | p_ctx->priv->module = module; |
| 500 | p_ctx->tracks = &module->track; |
| 501 | |
| 502 | p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0); |
| 503 | if(!p_ctx->tracks[0]) |
| 504 | { |
| 505 | status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; |
| 506 | goto error; |
| 507 | } |
| 508 | p_ctx->tracks_num = 1; |
| 509 | |
| 510 | module->pf_parse_header = mpga_read_header; |
| 511 | if(!strcasecmp(extension, "aac" ) || !strcasecmp(extension, "adts" )) |
| 512 | module->pf_parse_header = adts_read_header; |
| 513 | |
| 514 | if ((status = mpga_sync(p_ctx)) != VC_CONTAINER_SUCCESS) |
| 515 | { |
| 516 | /* An error here probably means it's not an mpga file at all */ |
| 517 | if(status == VC_CONTAINER_ERROR_FORMAT_INVALID) |
| 518 | status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
| 519 | goto error; |
| 520 | } |
| 521 | |
| 522 | /* If we got this far, we're probably dealing with an mpeg audio file */ |
| 523 | track = p_ctx->tracks[0]; |
| 524 | track->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO; |
| 525 | track->format->codec = VC_CONTAINER_CODEC_MPGA; |
| 526 | if(module->pf_parse_header == adts_read_header) |
| 527 | { |
| 528 | uint8_t * = track->format->extradata = module->extradata; |
| 529 | unsigned int sr_id; |
| 530 | for( sr_id = 0; sr_id < 13; sr_id++ ) |
| 531 | if( mpga_sample_rate_adts[sr_id] == module->sample_rate ) break; |
| 532 | extra[0] = (module->version << 3) | ((sr_id & 0xe) >> 1); |
| 533 | extra[1] = ((sr_id & 0x1) << 7) | (module->channels << 3); |
| 534 | track->format->extradata_size = 2; |
| 535 | track->format->codec = VC_CONTAINER_CODEC_MP4A; |
| 536 | } |
| 537 | track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED; |
| 538 | track->is_enabled = true; |
| 539 | track->format->type->audio.channels = module->channels; |
| 540 | track->format->type->audio.sample_rate = module->sample_rate; |
| 541 | track->format->type->audio.bits_per_sample = 0; |
| 542 | track->format->type->audio.block_align = 1; |
| 543 | |
| 544 | module->data_offset = STREAM_POSITION(p_ctx); |
| 545 | |
| 546 | /* Look for VBR headers within the first frame */ |
| 547 | status = mpga_read_vbr_headers(p_ctx); |
| 548 | if (status && status != VC_CONTAINER_ERROR_NOT_FOUND) goto error; |
| 549 | |
| 550 | /* If we couldn't get this information from VBR headers, try to determine |
| 551 | file size, bitrate, number of frames and duration */ |
| 552 | if (!module->data_size) |
| 553 | module->data_size = MAX(p_ctx->priv->io->size - module->data_offset, INT64_C(0)); |
| 554 | |
| 555 | if (!module->bitrate) |
| 556 | { |
| 557 | if (STREAM_SEEKABLE(p_ctx)) |
| 558 | { |
| 559 | /* Scan past a few hundred frames (audio will often have |
| 560 | silence in the beginning so we need to see more than |
| 561 | just a few frames) and estimate bitrate */ |
| 562 | for (i = 0; i < 256; ++i) |
| 563 | if (mpga_reader_read(p_ctx, NULL, VC_CONTAINER_READ_FLAG_SKIP)) break; |
| 564 | /* Seek back to start of data */ |
| 565 | SEEK(p_ctx, module->data_offset); |
| 566 | module->frame_index = 0; |
| 567 | module->frame_offset = INT64_C(0); |
| 568 | module->frame_time_pos = mpga_calculate_frame_time(p_ctx); |
| 569 | } |
| 570 | else |
| 571 | { |
| 572 | /* Bitrate will be correct for CBR only */ |
| 573 | module->bitrate = module->frame_bitrate; |
| 574 | } |
| 575 | } |
| 576 | |
| 577 | track->format->bitrate = module->bitrate; |
| 578 | |
| 579 | if (!module->num_frames) |
| 580 | { |
| 581 | module->num_frames = (module->data_size * module->sample_rate * 8LL) / |
| 582 | (module->bitrate * module->frame_size_samples); |
| 583 | } |
| 584 | |
| 585 | if (!p_ctx->duration && module->bitrate) |
| 586 | { |
| 587 | p_ctx->duration = (INT64_C(8000000) * module->data_size) / module->bitrate; |
| 588 | } |
| 589 | |
| 590 | p_ctx->priv->pf_close = mpga_reader_close; |
| 591 | p_ctx->priv->pf_read = mpga_reader_read; |
| 592 | p_ctx->priv->pf_seek = mpga_reader_seek; |
| 593 | |
| 594 | if(STREAM_SEEKABLE(p_ctx)) p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK; |
| 595 | |
| 596 | if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) goto error; |
| 597 | return VC_CONTAINER_SUCCESS; |
| 598 | |
| 599 | error: |
| 600 | if(status == VC_CONTAINER_SUCCESS || status == VC_CONTAINER_ERROR_EOS) |
| 601 | status = VC_CONTAINER_ERROR_FORMAT_INVALID; |
| 602 | LOG_DEBUG(p_ctx, "error opening stream (%i)" , status); |
| 603 | if (p_ctx->tracks_num != 0) |
| 604 | vc_container_free_track(p_ctx, p_ctx->tracks[0]); |
| 605 | p_ctx->tracks = NULL; |
| 606 | p_ctx->tracks_num = 0; |
| 607 | if (module) free(module); |
| 608 | p_ctx->priv->module = NULL; |
| 609 | return status; |
| 610 | } |
| 611 | |
| 612 | /******************************************************************************** |
| 613 | Entrypoint function |
| 614 | ********************************************************************************/ |
| 615 | |
| 616 | #if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__) |
| 617 | # pragma weak reader_open mpga_reader_open |
| 618 | #endif |
| 619 | |