xref: /third_party/ffmpeg/libavformat/lxfdec.c (revision cabdff1a)
1/*
2 * LXF demuxer
3 * Copyright (c) 2010 Tomas Härdin
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <inttypes.h>
23
24#include "libavutil/intreadwrite.h"
25#include "libavcodec/bytestream.h"
26#include "avformat.h"
27#include "demux.h"
28#include "internal.h"
29
30#define LXF_MAX_PACKET_HEADER_SIZE 256
31#define LXF_HEADER_DATA_SIZE    120
32#define LXF_IDENT               "LEITCH\0"
33#define LXF_IDENT_LENGTH        8
34#define LXF_SAMPLERATE          48000
35
36static const AVCodecTag lxf_tags[] = {
37    { AV_CODEC_ID_MJPEG,       0 },
38    { AV_CODEC_ID_MPEG1VIDEO,  1 },
39    { AV_CODEC_ID_MPEG2VIDEO,  2 },    //MpMl, 4:2:0
40    { AV_CODEC_ID_MPEG2VIDEO,  3 },    //MpPl, 4:2:2
41    { AV_CODEC_ID_DVVIDEO,     4 },    //DV25
42    { AV_CODEC_ID_DVVIDEO,     5 },    //DVCPRO
43    { AV_CODEC_ID_DVVIDEO,     6 },    //DVCPRO50
44    { AV_CODEC_ID_RAWVIDEO,    7 },    //AV_PIX_FMT_ARGB, where alpha is used for chroma keying
45    { AV_CODEC_ID_RAWVIDEO,    8 },    //16-bit chroma key
46    { AV_CODEC_ID_MPEG2VIDEO,  9 },    //4:2:2 CBP ("Constrained Bytes per Gop")
47    { AV_CODEC_ID_NONE,        0 },
48};
49
50typedef struct LXFDemuxContext {
51    int channels;                       ///< number of audio channels. zero means no audio
52    int frame_number;                   ///< current video frame
53    uint32_t video_format, packet_type, extended_size;
54} LXFDemuxContext;
55
56static int lxf_probe(const AVProbeData *p)
57{
58    if (!memcmp(p->buf, LXF_IDENT, LXF_IDENT_LENGTH))
59        return AVPROBE_SCORE_MAX;
60
61    return 0;
62}
63
64/**
65 * Verify the checksum of an LXF packet header
66 *
67 * @param[in] header the packet header to check
68 * @return zero if the checksum is OK, non-zero otherwise
69 */
70static int check_checksum(const uint8_t *header, int size)
71{
72    int x;
73    uint32_t sum = 0;
74
75    for (x = 0; x < size; x += 4)
76        sum += AV_RL32(&header[x]);
77
78    return sum;
79}
80
81/**
82 * Read input until we find the next ident. If found, copy it to the header buffer
83 *
84 * @param[out] header where to copy the ident to
85 * @return 0 if an ident was found, < 0 on I/O error
86 */
87static int lxf_sync(AVFormatContext *s, uint8_t *header)
88{
89    uint8_t buf[LXF_IDENT_LENGTH];
90    int ret;
91
92    if ((ret = avio_read(s->pb, buf, LXF_IDENT_LENGTH)) != LXF_IDENT_LENGTH)
93        return ret < 0 ? ret : AVERROR_EOF;
94
95    while (memcmp(buf, LXF_IDENT, LXF_IDENT_LENGTH)) {
96        if (avio_feof(s->pb))
97            return AVERROR_EOF;
98
99        memmove(buf, &buf[1], LXF_IDENT_LENGTH-1);
100        buf[LXF_IDENT_LENGTH-1] = avio_r8(s->pb);
101    }
102
103    memcpy(header, LXF_IDENT, LXF_IDENT_LENGTH);
104
105    return 0;
106}
107
108/**
109 * Read and checksum the next packet header
110 *
111 * @return the size of the payload following the header or < 0 on failure
112 */
113static int get_packet_header(AVFormatContext *s)
114{
115    LXFDemuxContext *lxf = s->priv_data;
116    AVIOContext   *pb  = s->pb;
117    int track_size, samples, ret;
118    uint32_t version, audio_format, header_size, channels, tmp;
119    AVStream *st;
120    uint8_t header[LXF_MAX_PACKET_HEADER_SIZE];
121    const uint8_t *p = header + LXF_IDENT_LENGTH;
122
123    //find and read the ident
124    if ((ret = lxf_sync(s, header)) < 0)
125        return ret;
126
127    ret = avio_read(pb, header + LXF_IDENT_LENGTH, 8);
128    if (ret != 8)
129        return ret < 0 ? ret : AVERROR_EOF;
130
131    version     = bytestream_get_le32(&p);
132    header_size = bytestream_get_le32(&p);
133    if (version > 1)
134        avpriv_request_sample(s, "Format version %"PRIu32, version);
135
136    if (header_size < (version ? 72 : 60) ||
137        header_size > LXF_MAX_PACKET_HEADER_SIZE ||
138        (header_size & 3)) {
139        av_log(s, AV_LOG_ERROR, "Invalid header size 0x%"PRIx32"\n", header_size);
140        return AVERROR_INVALIDDATA;
141    }
142
143    //read the rest of the packet header
144    if ((ret = avio_read(pb, header + (p - header),
145                          header_size - (p - header))) !=
146                          header_size - (p - header))
147        return ret < 0 ? ret : AVERROR_EOF;
148
149    if (check_checksum(header, header_size))
150        av_log(s, AV_LOG_ERROR, "checksum error\n");
151
152    lxf->packet_type = bytestream_get_le32(&p);
153    p += version ? 20 : 12;
154
155    lxf->extended_size = 0;
156    switch (lxf->packet_type) {
157    case 0:
158        //video
159        lxf->video_format = bytestream_get_le32(&p);
160        ret               = bytestream_get_le32(&p);
161        //skip VBI data and metadata
162        avio_skip(pb, (int64_t)(uint32_t)AV_RL32(p + 4) +
163                      (int64_t)(uint32_t)AV_RL32(p + 12));
164        break;
165    case 1:
166        //audio
167        if (s->nb_streams < 2) {
168            av_log(s, AV_LOG_INFO, "got audio packet, but no audio stream present\n");
169            break;
170        }
171
172        if (version == 0)
173            p += 8;
174        audio_format = bytestream_get_le32(&p);
175        channels     = bytestream_get_le32(&p);
176        track_size   = bytestream_get_le32(&p);
177
178        st = s->streams[1];
179
180        //set codec based on specified audio bitdepth
181        //we only support tightly packed 16-, 20-, 24- and 32-bit PCM at the moment
182        st->codecpar->bits_per_coded_sample = (audio_format >> 6) & 0x3F;
183
184        if (st->codecpar->bits_per_coded_sample != (audio_format & 0x3F)) {
185            avpriv_report_missing_feature(s, "Not tightly packed PCM");
186            return AVERROR_PATCHWELCOME;
187        }
188
189        switch (st->codecpar->bits_per_coded_sample) {
190        case 16: st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE_PLANAR; break;
191        case 20: st->codecpar->codec_id = AV_CODEC_ID_PCM_LXF;   break;
192        case 24: st->codecpar->codec_id = AV_CODEC_ID_PCM_S24LE_PLANAR; break;
193        case 32: st->codecpar->codec_id = AV_CODEC_ID_PCM_S32LE_PLANAR; break;
194        default:
195            avpriv_report_missing_feature(s, "PCM not 16-, 20-, 24- or 32-bits");
196            return AVERROR_PATCHWELCOME;
197        }
198
199        samples = track_size * 8LL / st->codecpar->bits_per_coded_sample;
200
201        //use audio packet size to determine video standard
202        //for NTSC we have one 8008-sample audio frame per five video frames
203        if (samples == LXF_SAMPLERATE * 5005 / 30000) {
204            avpriv_set_pts_info(s->streams[0], 64, 1001, 30000);
205        } else {
206            //assume PAL, but warn if we don't have 1920 samples
207            if (samples != LXF_SAMPLERATE / 25)
208                av_log(s, AV_LOG_WARNING,
209                       "video doesn't seem to be PAL or NTSC. guessing PAL\n");
210
211            avpriv_set_pts_info(s->streams[0], 64, 1, 25);
212        }
213
214        if (av_popcount(channels) * (uint64_t)track_size > INT_MAX)
215            return AVERROR_INVALIDDATA;
216        //TODO: warning if track mask != (1 << channels) - 1?
217        ret = av_popcount(channels) * track_size;
218
219        break;
220    default:
221        tmp = bytestream_get_le32(&p);
222        ret = bytestream_get_le32(&p);
223        if (tmp == 1)
224            lxf->extended_size = bytestream_get_le32(&p);
225        break;
226    }
227
228    return ret;
229}
230
231static int lxf_read_header(AVFormatContext *s)
232{
233    LXFDemuxContext *lxf = s->priv_data;
234    AVIOContext   *pb  = s->pb;
235    uint8_t header_data[LXF_HEADER_DATA_SIZE];
236    int ret;
237    AVStream *st;
238    uint32_t video_params, disk_params;
239    uint16_t record_date, expiration_date;
240
241    if ((ret = get_packet_header(s)) < 0)
242        return ret;
243
244    if (ret != LXF_HEADER_DATA_SIZE) {
245        av_log(s, AV_LOG_ERROR, "expected %d B size header, got %d\n",
246               LXF_HEADER_DATA_SIZE, ret);
247        return AVERROR_INVALIDDATA;
248    }
249
250    if ((ret = avio_read(pb, header_data, LXF_HEADER_DATA_SIZE)) != LXF_HEADER_DATA_SIZE)
251        return ret < 0 ? ret : AVERROR_EOF;
252
253    if (!(st = avformat_new_stream(s, NULL)))
254        return AVERROR(ENOMEM);
255
256    st->duration          = AV_RL32(&header_data[32]);
257    video_params          = AV_RL32(&header_data[40]);
258    record_date           = AV_RL16(&header_data[56]);
259    expiration_date       = AV_RL16(&header_data[58]);
260    disk_params           = AV_RL32(&header_data[116]);
261
262    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
263    st->codecpar->bit_rate   = 1000000 * ((video_params >> 14) & 0xFF);
264    st->codecpar->codec_tag  = video_params & 0xF;
265    st->codecpar->codec_id   = ff_codec_get_id(lxf_tags, st->codecpar->codec_tag);
266    ffstream(st)->need_parsing = AVSTREAM_PARSE_HEADERS;
267
268    av_log(s, AV_LOG_DEBUG, "record: %x = %i-%02i-%02i\n",
269           record_date, 1900 + (record_date & 0x7F), (record_date >> 7) & 0xF,
270           (record_date >> 11) & 0x1F);
271
272    av_log(s, AV_LOG_DEBUG, "expire: %x = %i-%02i-%02i\n",
273           expiration_date, 1900 + (expiration_date & 0x7F), (expiration_date >> 7) & 0xF,
274           (expiration_date >> 11) & 0x1F);
275
276    if ((video_params >> 22) & 1)
277        av_log(s, AV_LOG_WARNING, "VBI data not yet supported\n");
278
279    if ((lxf->channels = 1 << (disk_params >> 4 & 3) + 1)) {
280        if (!(st = avformat_new_stream(s, NULL)))
281            return AVERROR(ENOMEM);
282
283        st->codecpar->codec_type  = AVMEDIA_TYPE_AUDIO;
284        st->codecpar->sample_rate = LXF_SAMPLERATE;
285        st->codecpar->ch_layout.nb_channels = lxf->channels;
286
287        avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
288    }
289
290    avio_skip(s->pb, lxf->extended_size);
291
292    return 0;
293}
294
295static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt)
296{
297    LXFDemuxContext *lxf = s->priv_data;
298    AVIOContext   *pb  = s->pb;
299    uint32_t stream;
300    int ret, ret2;
301
302    if ((ret = get_packet_header(s)) < 0)
303        return ret;
304
305    stream = lxf->packet_type;
306
307    if (stream > 1) {
308        av_log(s, AV_LOG_WARNING,
309               "got packet with illegal stream index %"PRIu32"\n", stream);
310        return FFERROR_REDO;
311    }
312
313    if (stream == 1 && s->nb_streams < 2) {
314        av_log(s, AV_LOG_ERROR, "got audio packet without having an audio stream\n");
315        return AVERROR_INVALIDDATA;
316    }
317
318    if ((ret2 = av_new_packet(pkt, ret)) < 0)
319        return ret2;
320
321    if ((ret2 = avio_read(pb, pkt->data, ret)) != ret) {
322        return ret2 < 0 ? ret2 : AVERROR_EOF;
323    }
324
325    pkt->stream_index = stream;
326
327    if (!stream) {
328        //picture type (0 = closed I, 1 = open I, 2 = P, 3 = B)
329        if (((lxf->video_format >> 22) & 0x3) < 2)
330            pkt->flags |= AV_PKT_FLAG_KEY;
331
332        pkt->dts = lxf->frame_number++;
333    }
334
335    return ret;
336}
337
338const AVInputFormat ff_lxf_demuxer = {
339    .name           = "lxf",
340    .long_name      = NULL_IF_CONFIG_SMALL("VR native stream (LXF)"),
341    .priv_data_size = sizeof(LXFDemuxContext),
342    .read_probe     = lxf_probe,
343    .read_header    = lxf_read_header,
344    .read_packet    = lxf_read_packet,
345    .codec_tag      = (const AVCodecTag* const []){lxf_tags, 0},
346};
347