From 779951cd2c1b1efaf3d46efeb53fb23fc69bd0e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reimar=20D=C3=B6ffinger?= Date: Sat, 24 Mar 2012 16:47:33 +0100 Subject: [PATCH 1/2] lxf: Support version 1 files Signed-off-by: Luca Barbato --- libavformat/lxfdec.c | 93 ++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/libavformat/lxfdec.c b/libavformat/lxfdec.c index a10dcca08f..75be218f3d 100644 --- a/libavformat/lxfdec.c +++ b/libavformat/lxfdec.c @@ -20,10 +20,11 @@ */ #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 @@ -48,6 +49,7 @@ 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 +66,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; @@ -105,40 +107,58 @@ 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 = header + LXF_IDENT_LENGTH; //find and read the ident if ((ret = sync(s, header)) < 0) return ret; - //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) { + ret = avio_read(pb, header + LXF_IDENT_LENGTH, 8); + if (ret != 8) return ret < 0 ? ret : AVERROR_EOF; + + version = bytestream_get_le32(&p); + header_size = bytestream_get_le32(&p); + if (version > 1) + avpriv_request_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; } - if (check_checksum(header)) + //read the rest of the packet header + ret = avio_read(pb, header + (p - header), header_size - (p - header)); + if (ret != header_size - (p - header)) + return ret < 0 ? ret : AVERROR_EOF; + + 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 @@ -147,12 +167,17 @@ static int get_packet_header(AVFormatContext *s, uint8_t *header, uint32_t *form 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; } @@ -168,7 +193,6 @@ static int get_packet_header(AVFormatContext *s, uint8_t *header, uint32_t *form 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) { @@ -253,10 +281,7 @@ 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; } @@ -282,15 +307,15 @@ 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; + uint8_t *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); @@ -327,7 +352,7 @@ static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt) deplanarize(lxf, ast, pkt->data, ret); } else { //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++; From 839df90c718dcab9b9e91ca3c7e73479b3e8103c Mon Sep 17 00:00:00 2001 From: Carl Eugen Hoyos Date: Thu, 16 Aug 2012 10:20:25 +0200 Subject: [PATCH 2/2] lxf: Support 16-channel files Reported, analyzed and tested by Gabriel Gerard. Signed-off-by: Luca Barbato --- libavformat/lxfdec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/lxfdec.c b/libavformat/lxfdec.c index 75be218f3d..f29b773d6e 100644 --- a/libavformat/lxfdec.c +++ b/libavformat/lxfdec.c @@ -270,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);