2010-10-01 14:08:24 +03:00
|
|
|
/*
|
|
|
|
* LXF demuxer
|
|
|
|
* Copyright (c) 2010 Tomas Härdin
|
|
|
|
*
|
|
|
|
* This file is part of FFmpeg.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* 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 FFmpeg; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
2014-03-10 17:35:59 +03:00
|
|
|
#include <inttypes.h>
|
|
|
|
|
2010-10-01 14:08:24 +03:00
|
|
|
#include "libavutil/intreadwrite.h"
|
2012-03-24 18:47:33 +03:00
|
|
|
#include "libavcodec/bytestream.h"
|
2010-10-01 14:08:24 +03:00
|
|
|
#include "avformat.h"
|
2011-11-29 21:28:15 +03:00
|
|
|
#include "internal.h"
|
2010-10-01 14:08:24 +03:00
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
#define LXF_MAX_PACKET_HEADER_SIZE 256
|
2010-10-01 14:08:24 +03:00
|
|
|
#define LXF_HEADER_DATA_SIZE 120
|
|
|
|
#define LXF_IDENT "LEITCH\0"
|
|
|
|
#define LXF_IDENT_LENGTH 8
|
|
|
|
#define LXF_SAMPLERATE 48000
|
|
|
|
|
|
|
|
static const AVCodecTag lxf_tags[] = {
|
2012-08-05 12:11:04 +03:00
|
|
|
{ AV_CODEC_ID_MJPEG, 0 },
|
|
|
|
{ AV_CODEC_ID_MPEG1VIDEO, 1 },
|
|
|
|
{ AV_CODEC_ID_MPEG2VIDEO, 2 }, //MpMl, 4:2:0
|
|
|
|
{ AV_CODEC_ID_MPEG2VIDEO, 3 }, //MpPl, 4:2:2
|
|
|
|
{ AV_CODEC_ID_DVVIDEO, 4 }, //DV25
|
|
|
|
{ AV_CODEC_ID_DVVIDEO, 5 }, //DVCPRO
|
|
|
|
{ AV_CODEC_ID_DVVIDEO, 6 }, //DVCPRO50
|
2012-10-06 13:10:34 +03:00
|
|
|
{ AV_CODEC_ID_RAWVIDEO, 7 }, //AV_PIX_FMT_ARGB, where alpha is used for chroma keying
|
2012-08-05 12:11:04 +03:00
|
|
|
{ AV_CODEC_ID_RAWVIDEO, 8 }, //16-bit chroma key
|
|
|
|
{ AV_CODEC_ID_MPEG2VIDEO, 9 }, //4:2:2 CBP ("Constrained Bytes per Gop")
|
|
|
|
{ AV_CODEC_ID_NONE, 0 },
|
2010-10-01 14:08:24 +03:00
|
|
|
};
|
|
|
|
|
2014-09-22 10:19:33 +03:00
|
|
|
typedef struct LXFDemuxContext {
|
2010-10-01 14:08:24 +03:00
|
|
|
int channels; ///< number of audio channels. zero means no audio
|
|
|
|
int frame_number; ///< current video frame
|
2012-03-24 18:47:33 +03:00
|
|
|
uint32_t video_format, packet_type, extended_size;
|
2010-10-01 14:08:24 +03:00
|
|
|
} LXFDemuxContext;
|
|
|
|
|
2019-03-21 02:18:37 +02:00
|
|
|
static int lxf_probe(const AVProbeData *p)
|
2010-10-01 14:08:24 +03:00
|
|
|
{
|
|
|
|
if (!memcmp(p->buf, LXF_IDENT, LXF_IDENT_LENGTH))
|
|
|
|
return AVPROBE_SCORE_MAX;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Verify the checksum of an LXF packet header
|
|
|
|
*
|
|
|
|
* @param[in] header the packet header to check
|
|
|
|
* @return zero if the checksum is OK, non-zero otherwise
|
|
|
|
*/
|
2012-03-24 18:47:33 +03:00
|
|
|
static int check_checksum(const uint8_t *header, int size)
|
2010-10-01 14:08:24 +03:00
|
|
|
{
|
|
|
|
int x;
|
|
|
|
uint32_t sum = 0;
|
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
for (x = 0; x < size; x += 4)
|
2010-10-01 14:08:24 +03:00
|
|
|
sum += AV_RL32(&header[x]);
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read input until we find the next ident. If found, copy it to the header buffer
|
|
|
|
*
|
|
|
|
* @param[out] header where to copy the ident to
|
|
|
|
* @return 0 if an ident was found, < 0 on I/O error
|
|
|
|
*/
|
2014-11-26 00:49:58 +02:00
|
|
|
static int lxf_sync(AVFormatContext *s, uint8_t *header)
|
2010-10-01 14:08:24 +03:00
|
|
|
{
|
|
|
|
uint8_t buf[LXF_IDENT_LENGTH];
|
|
|
|
int ret;
|
|
|
|
|
2011-02-21 17:43:01 +02:00
|
|
|
if ((ret = avio_read(s->pb, buf, LXF_IDENT_LENGTH)) != LXF_IDENT_LENGTH)
|
2010-10-01 14:08:24 +03:00
|
|
|
return ret < 0 ? ret : AVERROR_EOF;
|
|
|
|
|
|
|
|
while (memcmp(buf, LXF_IDENT, LXF_IDENT_LENGTH)) {
|
2014-08-07 23:12:41 +03:00
|
|
|
if (avio_feof(s->pb))
|
2010-10-01 14:08:24 +03:00
|
|
|
return AVERROR_EOF;
|
|
|
|
|
|
|
|
memmove(buf, &buf[1], LXF_IDENT_LENGTH-1);
|
2011-02-21 17:43:01 +02:00
|
|
|
buf[LXF_IDENT_LENGTH-1] = avio_r8(s->pb);
|
2010-10-01 14:08:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(header, LXF_IDENT, LXF_IDENT_LENGTH);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read and checksum the next packet header
|
|
|
|
*
|
|
|
|
* @return the size of the payload following the header or < 0 on failure
|
|
|
|
*/
|
2012-03-24 18:47:33 +03:00
|
|
|
static int get_packet_header(AVFormatContext *s)
|
2010-10-01 14:08:24 +03:00
|
|
|
{
|
2012-03-24 18:47:33 +03:00
|
|
|
LXFDemuxContext *lxf = s->priv_data;
|
2011-02-20 12:04:12 +02:00
|
|
|
AVIOContext *pb = s->pb;
|
2010-10-01 14:08:24 +03:00
|
|
|
int track_size, samples, ret;
|
2012-03-24 18:47:33 +03:00
|
|
|
uint32_t version, audio_format, header_size, channels, tmp;
|
2010-10-01 14:08:24 +03:00
|
|
|
AVStream *st;
|
2012-03-24 18:47:33 +03:00
|
|
|
uint8_t header[LXF_MAX_PACKET_HEADER_SIZE];
|
2012-03-24 18:47:33 +03:00
|
|
|
const uint8_t *p = header + LXF_IDENT_LENGTH;
|
2010-10-01 14:08:24 +03:00
|
|
|
|
|
|
|
//find and read the ident
|
2014-11-26 00:49:58 +02:00
|
|
|
if ((ret = lxf_sync(s, header)) < 0)
|
2010-10-01 14:08:24 +03:00
|
|
|
return ret;
|
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
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)
|
2015-12-15 20:59:14 +02:00
|
|
|
avpriv_request_sample(s, "Format version %"PRIu32, version);
|
2012-03-24 18:47:33 +03:00
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
if (header_size < (version ? 72 : 60) ||
|
|
|
|
header_size > LXF_MAX_PACKET_HEADER_SIZE ||
|
|
|
|
(header_size & 3)) {
|
2014-03-10 17:35:59 +03:00
|
|
|
av_log(s, AV_LOG_ERROR, "Invalid header size 0x%"PRIx32"\n", header_size);
|
2012-03-24 18:47:33 +03:00
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
}
|
|
|
|
|
2010-10-01 14:08:24 +03:00
|
|
|
//read the rest of the packet header
|
2012-03-24 18:47:33 +03:00
|
|
|
if ((ret = avio_read(pb, header + (p - header),
|
|
|
|
header_size - (p - header))) !=
|
2013-09-27 13:29:36 +03:00
|
|
|
header_size - (p - header))
|
2010-10-01 14:08:24 +03:00
|
|
|
return ret < 0 ? ret : AVERROR_EOF;
|
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
if (check_checksum(header, header_size))
|
2010-10-01 14:08:24 +03:00
|
|
|
av_log(s, AV_LOG_ERROR, "checksum error\n");
|
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
lxf->packet_type = bytestream_get_le32(&p);
|
|
|
|
p += version ? 20 : 12;
|
2010-10-01 14:08:24 +03:00
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
lxf->extended_size = 0;
|
|
|
|
switch (lxf->packet_type) {
|
2010-10-01 14:08:24 +03:00
|
|
|
case 0:
|
|
|
|
//video
|
2012-03-24 18:47:33 +03:00
|
|
|
lxf->video_format = bytestream_get_le32(&p);
|
|
|
|
ret = bytestream_get_le32(&p);
|
2010-10-01 14:08:24 +03:00
|
|
|
//skip VBI data and metadata
|
2012-03-24 18:47:33 +03:00
|
|
|
avio_skip(pb, (int64_t)(uint32_t)AV_RL32(p + 4) +
|
|
|
|
(int64_t)(uint32_t)AV_RL32(p + 12));
|
2010-10-01 14:08:24 +03:00
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
//audio
|
2013-06-25 17:42:02 +03:00
|
|
|
if (s->nb_streams < 2) {
|
2010-10-01 14:08:24 +03:00
|
|
|
av_log(s, AV_LOG_INFO, "got audio packet, but no audio stream present\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
if (version == 0)
|
|
|
|
p += 8;
|
2012-03-24 18:47:33 +03:00
|
|
|
audio_format = bytestream_get_le32(&p);
|
|
|
|
channels = bytestream_get_le32(&p);
|
|
|
|
track_size = bytestream_get_le32(&p);
|
|
|
|
|
2013-06-25 17:42:02 +03:00
|
|
|
st = s->streams[1];
|
|
|
|
|
2010-10-01 14:08:24 +03:00
|
|
|
//set codec based on specified audio bitdepth
|
|
|
|
//we only support tightly packed 16-, 20-, 24- and 32-bit PCM at the moment
|
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
|
|
|
st->codecpar->bits_per_coded_sample = (audio_format >> 6) & 0x3F;
|
2010-10-01 14:08:24 +03:00
|
|
|
|
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
|
|
|
if (st->codecpar->bits_per_coded_sample != (audio_format & 0x3F)) {
|
2015-12-16 19:01:34 +02:00
|
|
|
avpriv_report_missing_feature(s, "Not tightly packed PCM");
|
2010-10-01 14:08:24 +03:00
|
|
|
return AVERROR_PATCHWELCOME;
|
|
|
|
}
|
|
|
|
|
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
|
|
|
switch (st->codecpar->bits_per_coded_sample) {
|
|
|
|
case 16: st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE_PLANAR; break;
|
|
|
|
case 20: st->codecpar->codec_id = AV_CODEC_ID_PCM_LXF; break;
|
|
|
|
case 24: st->codecpar->codec_id = AV_CODEC_ID_PCM_S24LE_PLANAR; break;
|
|
|
|
case 32: st->codecpar->codec_id = AV_CODEC_ID_PCM_S32LE_PLANAR; break;
|
2010-10-01 14:08:24 +03:00
|
|
|
default:
|
2015-12-16 19:01:34 +02:00
|
|
|
avpriv_report_missing_feature(s, "PCM not 16-, 20-, 24- or 32-bits");
|
2010-10-01 14:08:24 +03:00
|
|
|
return AVERROR_PATCHWELCOME;
|
|
|
|
}
|
|
|
|
|
2021-01-14 23:08:25 +02:00
|
|
|
samples = track_size * 8LL / st->codecpar->bits_per_coded_sample;
|
2010-10-01 14:08:24 +03:00
|
|
|
|
|
|
|
//use audio packet size to determine video standard
|
|
|
|
//for NTSC we have one 8008-sample audio frame per five video frames
|
|
|
|
if (samples == LXF_SAMPLERATE * 5005 / 30000) {
|
2011-11-29 21:28:15 +03:00
|
|
|
avpriv_set_pts_info(s->streams[0], 64, 1001, 30000);
|
2010-10-01 14:08:24 +03:00
|
|
|
} else {
|
|
|
|
//assume PAL, but warn if we don't have 1920 samples
|
|
|
|
if (samples != LXF_SAMPLERATE / 25)
|
|
|
|
av_log(s, AV_LOG_WARNING,
|
|
|
|
"video doesn't seem to be PAL or NTSC. guessing PAL\n");
|
|
|
|
|
2011-11-29 21:28:15 +03:00
|
|
|
avpriv_set_pts_info(s->streams[0], 64, 1, 25);
|
2010-10-01 14:08:24 +03:00
|
|
|
}
|
|
|
|
|
2021-01-14 23:08:25 +02:00
|
|
|
if (av_popcount(channels) * (uint64_t)track_size > INT_MAX)
|
|
|
|
return AVERROR_INVALIDDATA;
|
2010-10-01 14:08:24 +03:00
|
|
|
//TODO: warning if track mask != (1 << channels) - 1?
|
2012-03-24 18:47:33 +03:00
|
|
|
ret = av_popcount(channels) * track_size;
|
2010-10-01 14:08:24 +03:00
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
2012-03-24 18:47:33 +03:00
|
|
|
tmp = bytestream_get_le32(&p);
|
|
|
|
ret = bytestream_get_le32(&p);
|
|
|
|
if (tmp == 1)
|
|
|
|
lxf->extended_size = bytestream_get_le32(&p);
|
2010-10-01 14:08:24 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-12 15:20:36 +03:00
|
|
|
static int lxf_read_header(AVFormatContext *s)
|
2010-10-01 14:08:24 +03:00
|
|
|
{
|
|
|
|
LXFDemuxContext *lxf = s->priv_data;
|
2011-02-20 12:04:12 +02:00
|
|
|
AVIOContext *pb = s->pb;
|
2012-03-24 18:47:33 +03:00
|
|
|
uint8_t header_data[LXF_HEADER_DATA_SIZE];
|
2010-10-01 14:08:24 +03:00
|
|
|
int ret;
|
|
|
|
AVStream *st;
|
2012-03-24 18:47:33 +03:00
|
|
|
uint32_t video_params, disk_params;
|
2010-10-01 14:08:24 +03:00
|
|
|
uint16_t record_date, expiration_date;
|
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
if ((ret = get_packet_header(s)) < 0)
|
2010-10-01 14:08:24 +03:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (ret != LXF_HEADER_DATA_SIZE) {
|
|
|
|
av_log(s, AV_LOG_ERROR, "expected %d B size header, got %d\n",
|
|
|
|
LXF_HEADER_DATA_SIZE, ret);
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
}
|
|
|
|
|
2011-02-21 17:43:01 +02:00
|
|
|
if ((ret = avio_read(pb, header_data, LXF_HEADER_DATA_SIZE)) != LXF_HEADER_DATA_SIZE)
|
2010-10-01 14:08:24 +03:00
|
|
|
return ret < 0 ? ret : AVERROR_EOF;
|
|
|
|
|
2011-06-18 12:43:24 +03:00
|
|
|
if (!(st = avformat_new_stream(s, NULL)))
|
2011-04-06 09:18:16 +03:00
|
|
|
return AVERROR(ENOMEM);
|
2010-10-01 14:08:24 +03:00
|
|
|
|
|
|
|
st->duration = AV_RL32(&header_data[32]);
|
|
|
|
video_params = AV_RL32(&header_data[40]);
|
|
|
|
record_date = AV_RL16(&header_data[56]);
|
|
|
|
expiration_date = AV_RL16(&header_data[58]);
|
|
|
|
disk_params = AV_RL32(&header_data[116]);
|
|
|
|
|
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
|
|
|
st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
|
|
|
st->codecpar->bit_rate = 1000000 * ((video_params >> 14) & 0xFF);
|
|
|
|
st->codecpar->codec_tag = video_params & 0xF;
|
|
|
|
st->codecpar->codec_id = ff_codec_get_id(lxf_tags, st->codecpar->codec_tag);
|
2021-08-24 19:41:16 +02:00
|
|
|
ffstream(st)->need_parsing = AVSTREAM_PARSE_HEADERS;
|
2010-10-01 14:08:24 +03:00
|
|
|
|
|
|
|
av_log(s, AV_LOG_DEBUG, "record: %x = %i-%02i-%02i\n",
|
|
|
|
record_date, 1900 + (record_date & 0x7F), (record_date >> 7) & 0xF,
|
|
|
|
(record_date >> 11) & 0x1F);
|
|
|
|
|
|
|
|
av_log(s, AV_LOG_DEBUG, "expire: %x = %i-%02i-%02i\n",
|
|
|
|
expiration_date, 1900 + (expiration_date & 0x7F), (expiration_date >> 7) & 0xF,
|
|
|
|
(expiration_date >> 11) & 0x1F);
|
|
|
|
|
|
|
|
if ((video_params >> 22) & 1)
|
|
|
|
av_log(s, AV_LOG_WARNING, "VBI data not yet supported\n");
|
|
|
|
|
2012-08-16 11:20:25 +03:00
|
|
|
if ((lxf->channels = 1 << (disk_params >> 4 & 3) + 1)) {
|
2011-06-18 12:43:24 +03:00
|
|
|
if (!(st = avformat_new_stream(s, NULL)))
|
2011-04-06 09:18:16 +03:00
|
|
|
return AVERROR(ENOMEM);
|
2010-10-01 14:08:24 +03:00
|
|
|
|
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
|
|
|
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
|
|
|
st->codecpar->sample_rate = LXF_SAMPLERATE;
|
|
|
|
st->codecpar->channels = lxf->channels;
|
2010-10-01 14:08:24 +03:00
|
|
|
|
lavf: replace AVStream.codec with AVStream.codecpar
Currently, AVStream contains an embedded AVCodecContext instance, which
is used by demuxers to export stream parameters to the caller and by
muxers to receive stream parameters from the caller. It is also used
internally as the codec context that is passed to parsers.
In addition, it is also widely used by the callers as the decoding (when
demuxer) or encoding (when muxing) context, though this has been
officially discouraged since Libav 11.
There are multiple important problems with this approach:
- the fields in AVCodecContext are in general one of
* stream parameters
* codec options
* codec state
However, it's not clear which ones are which. It is consequently
unclear which fields are a demuxer allowed to set or a muxer allowed to
read. This leads to erratic behaviour depending on whether decoding or
encoding is being performed or not (and whether it uses the AVStream
embedded codec context).
- various synchronization issues arising from the fact that the same
context is used by several different APIs (muxers/demuxers,
parsers, bitstream filters and encoders/decoders) simultaneously, with
there being no clear rules for who can modify what and the different
processes being typically delayed with respect to each other.
- avformat_find_stream_info() making it necessary to support opening
and closing a single codec context multiple times, thus
complicating the semantics of freeing various allocated objects in the
codec context.
Those problems are resolved by replacing the AVStream embedded codec
context with a newly added AVCodecParameters instance, which stores only
the stream parameters exported by the demuxers or read by the muxers.
2014-06-18 21:42:52 +03:00
|
|
|
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
|
2010-10-01 14:08:24 +03:00
|
|
|
}
|
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
avio_skip(s->pb, lxf->extended_size);
|
2010-10-01 14:08:24 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|
|
|
{
|
|
|
|
LXFDemuxContext *lxf = s->priv_data;
|
2011-02-20 12:04:12 +02:00
|
|
|
AVIOContext *pb = s->pb;
|
2012-03-24 18:47:33 +03:00
|
|
|
uint32_t stream;
|
2010-10-01 14:08:24 +03:00
|
|
|
int ret, ret2;
|
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
if ((ret = get_packet_header(s)) < 0)
|
2010-10-01 14:08:24 +03:00
|
|
|
return ret;
|
|
|
|
|
2012-03-24 18:47:33 +03:00
|
|
|
stream = lxf->packet_type;
|
2010-10-01 14:08:24 +03:00
|
|
|
|
|
|
|
if (stream > 1) {
|
2014-03-10 17:35:59 +03:00
|
|
|
av_log(s, AV_LOG_WARNING,
|
|
|
|
"got packet with illegal stream index %"PRIu32"\n", stream);
|
2015-11-27 19:58:25 +02:00
|
|
|
return FFERROR_REDO;
|
2010-10-01 14:08:24 +03:00
|
|
|
}
|
|
|
|
|
2013-06-25 17:42:02 +03:00
|
|
|
if (stream == 1 && s->nb_streams < 2) {
|
2010-10-01 14:08:24 +03:00
|
|
|
av_log(s, AV_LOG_ERROR, "got audio packet without having an audio stream\n");
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret2 = av_new_packet(pkt, ret)) < 0)
|
|
|
|
return ret2;
|
|
|
|
|
2012-11-16 18:10:36 +03:00
|
|
|
if ((ret2 = avio_read(pb, pkt->data, ret)) != ret) {
|
2010-10-01 14:08:24 +03:00
|
|
|
return ret2 < 0 ? ret2 : AVERROR_EOF;
|
|
|
|
}
|
|
|
|
|
|
|
|
pkt->stream_index = stream;
|
|
|
|
|
2013-06-25 17:42:02 +03:00
|
|
|
if (!stream) {
|
2010-10-01 14:08:24 +03:00
|
|
|
//picture type (0 = closed I, 1 = open I, 2 = P, 3 = B)
|
2012-03-24 18:47:33 +03:00
|
|
|
if (((lxf->video_format >> 22) & 0x3) < 2)
|
2010-10-01 14:08:24 +03:00
|
|
|
pkt->flags |= AV_PKT_FLAG_KEY;
|
|
|
|
|
|
|
|
pkt->dts = lxf->frame_number++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-04-19 19:45:24 +02:00
|
|
|
const AVInputFormat ff_lxf_demuxer = {
|
2010-10-01 14:08:24 +03:00
|
|
|
.name = "lxf",
|
2012-07-25 00:51:41 +03:00
|
|
|
.long_name = NULL_IF_CONFIG_SMALL("VR native stream (LXF)"),
|
2010-10-01 14:08:24 +03:00
|
|
|
.priv_data_size = sizeof(LXFDemuxContext),
|
|
|
|
.read_probe = lxf_probe,
|
|
|
|
.read_header = lxf_read_header,
|
|
|
|
.read_packet = lxf_read_packet,
|
|
|
|
.codec_tag = (const AVCodecTag* const []){lxf_tags, 0},
|
|
|
|
};
|