diff options
Diffstat (limited to 'libavformat/lxfdec.c')
-rw-r--r-- | libavformat/lxfdec.c | 139 |
1 files changed, 70 insertions, 69 deletions
diff --git a/libavformat/lxfdec.c b/libavformat/lxfdec.c index a10dcca08f..90c49749a6 100644 --- a/libavformat/lxfdec.c +++ b/libavformat/lxfdec.c @@ -2,28 +2,29 @@ * LXF demuxer * Copyright (c) 2010 Tomas Härdin * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libavutil/intreadwrite.h" +#include "libavcodec/bytestream.h" #include "avformat.h" #include "internal.h" -#define LXF_PACKET_HEADER_SIZE 60 +#define LXF_MAX_PACKET_HEADER_SIZE 256 #define LXF_HEADER_DATA_SIZE 120 #define LXF_IDENT "LEITCH\0" #define LXF_IDENT_LENGTH 8 @@ -46,8 +47,8 @@ static const AVCodecTag lxf_tags[] = { typedef struct { int channels; ///< number of audio channels. zero means no audio - uint8_t temp[LXF_MAX_AUDIO_PACKET]; ///< temp buffer for de-planarizing the audio data int frame_number; ///< current video frame + uint32_t video_format, packet_type, extended_size; } LXFDemuxContext; static int lxf_probe(AVProbeData *p) @@ -64,12 +65,12 @@ static int lxf_probe(AVProbeData *p) * @param[in] header the packet header to check * @return zero if the checksum is OK, non-zero otherwise */ -static int check_checksum(const uint8_t *header) +static int check_checksum(const uint8_t *header, int size) { int x; uint32_t sum = 0; - for (x = 0; x < LXF_PACKET_HEADER_SIZE; x += 4) + for (x = 0; x < size; x += 4) sum += AV_RL32(&header[x]); return sum; @@ -90,7 +91,7 @@ static int sync(AVFormatContext *s, uint8_t *header) return ret < 0 ? ret : AVERROR_EOF; while (memcmp(buf, LXF_IDENT, LXF_IDENT_LENGTH)) { - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR_EOF; memmove(buf, &buf[1], LXF_IDENT_LENGTH-1); @@ -105,70 +106,93 @@ static int sync(AVFormatContext *s, uint8_t *header) /** * Read and checksum the next packet header * - * @param[out] header the read packet header - * @param[out] format context dependent format information * @return the size of the payload following the header or < 0 on failure */ -static int get_packet_header(AVFormatContext *s, uint8_t *header, uint32_t *format) +static int get_packet_header(AVFormatContext *s) { + LXFDemuxContext *lxf = s->priv_data; AVIOContext *pb = s->pb; int track_size, samples, ret; + uint32_t version, audio_format, header_size, channels, tmp; AVStream *st; + uint8_t header[LXF_MAX_PACKET_HEADER_SIZE]; + const uint8_t *p; //find and read the ident if ((ret = sync(s, header)) < 0) return ret; + ret = avio_read(pb, header + LXF_IDENT_LENGTH, 8); + if (ret != 8) + return ret < 0 ? ret : AVERROR_EOF; + + p = header + LXF_IDENT_LENGTH; + version = bytestream_get_le32(&p); + header_size = bytestream_get_le32(&p); + if (version > 1) + av_log_ask_for_sample(s, "Unknown format version %i\n", version); + if (header_size < (version ? 72 : 60) || + header_size > LXF_MAX_PACKET_HEADER_SIZE || + (header_size & 3)) { + av_log(s, AV_LOG_ERROR, "Invalid header size 0x%x\n", header_size); + return AVERROR_INVALIDDATA; + } + //read the rest of the packet header - if ((ret = avio_read(pb, header + LXF_IDENT_LENGTH, - LXF_PACKET_HEADER_SIZE - LXF_IDENT_LENGTH)) != - LXF_PACKET_HEADER_SIZE - LXF_IDENT_LENGTH) { + if ((ret = avio_read(pb, header + (p - header), + header_size - (p - header))) != + header_size - (p - header)) { return ret < 0 ? ret : AVERROR_EOF; } - if (check_checksum(header)) + if (check_checksum(header, header_size)) av_log(s, AV_LOG_ERROR, "checksum error\n"); - *format = AV_RL32(&header[32]); - ret = AV_RL32(&header[36]); + lxf->packet_type = bytestream_get_le32(&p); + p += version ? 20 : 12; - //type - switch (AV_RL32(&header[16])) { + lxf->extended_size = 0; + switch (lxf->packet_type) { case 0: //video + lxf->video_format = bytestream_get_le32(&p); + ret = bytestream_get_le32(&p); //skip VBI data and metadata - avio_skip(pb, (int64_t)(uint32_t)AV_RL32(&header[44]) + - (int64_t)(uint32_t)AV_RL32(&header[52])); + avio_skip(pb, (int64_t)(uint32_t)AV_RL32(p + 4) + + (int64_t)(uint32_t)AV_RL32(p + 12)); break; case 1: //audio - if (!(st = s->streams[1])) { + if (!s->streams || !(st = s->streams[1])) { av_log(s, AV_LOG_INFO, "got audio packet, but no audio stream present\n"); break; } + if (version == 0) p += 8; + audio_format = bytestream_get_le32(&p); + channels = bytestream_get_le32(&p); + track_size = bytestream_get_le32(&p); + //set codec based on specified audio bitdepth //we only support tightly packed 16-, 20-, 24- and 32-bit PCM at the moment - *format = AV_RL32(&header[40]); - st->codec->bits_per_coded_sample = (*format >> 6) & 0x3F; + st->codec->bits_per_coded_sample = (audio_format >> 6) & 0x3F; - if (st->codec->bits_per_coded_sample != (*format & 0x3F)) { + if (st->codec->bits_per_coded_sample != (audio_format & 0x3F)) { av_log(s, AV_LOG_WARNING, "only tightly packed PCM currently supported\n"); return AVERROR_PATCHWELCOME; } switch (st->codec->bits_per_coded_sample) { - case 16: st->codec->codec_id = AV_CODEC_ID_PCM_S16LE; break; + case 16: st->codec->codec_id = AV_CODEC_ID_PCM_S16LE_PLANAR; break; case 20: st->codec->codec_id = AV_CODEC_ID_PCM_LXF; break; - case 24: st->codec->codec_id = AV_CODEC_ID_PCM_S24LE; break; - case 32: st->codec->codec_id = AV_CODEC_ID_PCM_S32LE; break; + case 24: st->codec->codec_id = AV_CODEC_ID_PCM_S24LE_PLANAR; break; + case 32: st->codec->codec_id = AV_CODEC_ID_PCM_S32LE_PLANAR; break; default: av_log(s, AV_LOG_WARNING, "only 16-, 20-, 24- and 32-bit PCM currently supported\n"); return AVERROR_PATCHWELCOME; } - track_size = AV_RL32(&header[48]); samples = track_size * 8 / st->codec->bits_per_coded_sample; //use audio packet size to determine video standard @@ -185,10 +209,14 @@ static int get_packet_header(AVFormatContext *s, uint8_t *header, uint32_t *form } //TODO: warning if track mask != (1 << channels) - 1? - ret = av_popcount(AV_RL32(&header[44])) * track_size; + ret = av_popcount(channels) * track_size; break; default: + tmp = bytestream_get_le32(&p); + ret = bytestream_get_le32(&p); + if (tmp == 1) + lxf->extended_size = bytestream_get_le32(&p); break; } @@ -199,13 +227,13 @@ static int lxf_read_header(AVFormatContext *s) { LXFDemuxContext *lxf = s->priv_data; AVIOContext *pb = s->pb; - uint8_t header[LXF_PACKET_HEADER_SIZE], header_data[LXF_HEADER_DATA_SIZE]; + uint8_t header_data[LXF_HEADER_DATA_SIZE]; int ret; AVStream *st; - uint32_t format, video_params, disk_params; + uint32_t video_params, disk_params; uint16_t record_date, expiration_date; - if ((ret = get_packet_header(s, header, &format)) < 0) + if ((ret = get_packet_header(s)) < 0) return ret; if (ret != LXF_HEADER_DATA_SIZE) { @@ -242,7 +270,7 @@ static int lxf_read_header(AVFormatContext *s) if ((video_params >> 22) & 1) av_log(s, AV_LOG_WARNING, "VBI data not yet supported\n"); - if ((lxf->channels = (disk_params >> 2) & 0xF)) { + if ((lxf->channels = 1 << (disk_params >> 4 & 3) + 1)) { if (!(st = avformat_new_stream(s, NULL))) return AVERROR(ENOMEM); @@ -253,44 +281,23 @@ static int lxf_read_header(AVFormatContext *s) avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); } - if (format == 1) { - //skip extended field data - avio_skip(s->pb, (uint32_t)AV_RL32(&header[40])); - } + avio_skip(s->pb, lxf->extended_size); return 0; } -/** - * De-planerize the PCM data in lxf->temp - * FIXME: remove this once support for planar audio is added to libavcodec - * - * @param[out] out where to write the de-planerized data to - * @param[in] bytes the total size of the PCM data - */ -static void deplanarize(LXFDemuxContext *lxf, AVStream *ast, uint8_t *out, int bytes) -{ - int x, y, z, i, bytes_per_sample = ast->codec->bits_per_coded_sample >> 3; - - for (z = i = 0; z < lxf->channels; z++) - for (y = 0; y < bytes / bytes_per_sample / lxf->channels; y++) - for (x = 0; x < bytes_per_sample; x++, i++) - out[x + bytes_per_sample*(z + y*lxf->channels)] = lxf->temp[i]; -} - static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt) { LXFDemuxContext *lxf = s->priv_data; AVIOContext *pb = s->pb; - uint8_t header[LXF_PACKET_HEADER_SIZE], *buf; AVStream *ast = NULL; - uint32_t stream, format; + uint32_t stream; int ret, ret2; - if ((ret = get_packet_header(s, header, &format)) < 0) + if ((ret = get_packet_header(s)) < 0) return ret; - stream = AV_RL32(&header[16]); + stream = lxf->packet_type; if (stream > 1) { av_log(s, AV_LOG_WARNING, "got packet with illegal stream index %u\n", stream); @@ -312,22 +319,16 @@ static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt) if ((ret2 = av_new_packet(pkt, ret)) < 0) return ret2; - //read non-20-bit audio data into lxf->temp so we can deplanarize it - buf = ast && ast->codec->codec_id != AV_CODEC_ID_PCM_LXF ? lxf->temp : pkt->data; - - if ((ret2 = avio_read(pb, buf, ret)) != ret) { + if ((ret2 = avio_read(pb, pkt->data, ret)) != ret) { av_free_packet(pkt); return ret2 < 0 ? ret2 : AVERROR_EOF; } pkt->stream_index = stream; - if (ast) { - if(ast->codec->codec_id != AV_CODEC_ID_PCM_LXF) - deplanarize(lxf, ast, pkt->data, ret); - } else { + if (!ast) { //picture type (0 = closed I, 1 = open I, 2 = P, 3 = B) - if (((format >> 22) & 0x3) < 2) + if (((lxf->video_format >> 22) & 0x3) < 2) pkt->flags |= AV_PKT_FLAG_KEY; pkt->dts = lxf->frame_number++; |