mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-27 01:42:20 +00:00
mpeg: Add passing DVD navigation packets (startcode 0x1bf) to caller to allow better playback handling of DVDs.
The two types of packets (PCI and DSI) are passed untouched but combined by the new codec ID AV_CODEC_ID_DVD_NAV. The first 980 bytes in the packet contain the PCI data. The next 1018 are the DSI data. Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
parent
975fbd43ad
commit
9cde9f70ab
@ -743,6 +743,7 @@ OBJS-$(CONFIG_PNG_PARSER) += png_parser.o
|
|||||||
OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o \
|
OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o \
|
||||||
mpegaudiodecheader.o mpegaudiodata.o
|
mpegaudiodecheader.o mpegaudiodata.o
|
||||||
OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \
|
OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \
|
||||||
|
dvd_nav_parser.o \
|
||||||
mpeg12.o mpeg12data.o
|
mpeg12.o mpeg12data.o
|
||||||
OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o
|
OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o
|
||||||
OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o
|
OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o
|
||||||
|
@ -515,6 +515,7 @@ void avcodec_register_all(void)
|
|||||||
REGISTER_PARSER(DNXHD, dnxhd);
|
REGISTER_PARSER(DNXHD, dnxhd);
|
||||||
REGISTER_PARSER(DVBSUB, dvbsub);
|
REGISTER_PARSER(DVBSUB, dvbsub);
|
||||||
REGISTER_PARSER(DVDSUB, dvdsub);
|
REGISTER_PARSER(DVDSUB, dvdsub);
|
||||||
|
REGISTER_PARSER(DVD_NAV, dvd_nav);
|
||||||
REGISTER_PARSER(FLAC, flac);
|
REGISTER_PARSER(FLAC, flac);
|
||||||
REGISTER_PARSER(GSM, gsm);
|
REGISTER_PARSER(GSM, gsm);
|
||||||
REGISTER_PARSER(H261, h261);
|
REGISTER_PARSER(H261, h261);
|
||||||
|
@ -482,6 +482,8 @@ enum AVCodecID {
|
|||||||
AV_CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'),
|
AV_CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'),
|
||||||
AV_CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'),
|
AV_CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'),
|
||||||
AV_CODEC_ID_SMPTE_KLV = MKBETAG('K','L','V','A'),
|
AV_CODEC_ID_SMPTE_KLV = MKBETAG('K','L','V','A'),
|
||||||
|
AV_CODEC_ID_DVD_NAV = MKBETAG('D','N','A','V'),
|
||||||
|
|
||||||
|
|
||||||
AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it
|
AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it
|
||||||
|
|
||||||
|
@ -2525,6 +2525,12 @@ static const AVCodecDescriptor codec_descriptors[] = {
|
|||||||
.name = "klv",
|
.name = "klv",
|
||||||
.long_name = NULL_IF_CONFIG_SMALL("SMPTE 336M Key-Length-Value (KLV) metadata"),
|
.long_name = NULL_IF_CONFIG_SMALL("SMPTE 336M Key-Length-Value (KLV) metadata"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.id = AV_CODEC_ID_DVD_NAV,
|
||||||
|
.type = AVMEDIA_TYPE_DATA,
|
||||||
|
.name = "dvd_nav_packet",
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("DVD Nav packet"),
|
||||||
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
116
libavcodec/dvd_nav_parser.c
Normal file
116
libavcodec/dvd_nav_parser.c
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* DVD navigation block parser for FFmpeg
|
||||||
|
* Copyright (c) 2013 The FFmpeg Project
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "dsputil.h"
|
||||||
|
#include "get_bits.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
#define PCI_SIZE 980
|
||||||
|
#define DSI_SIZE 1018
|
||||||
|
|
||||||
|
/* parser definition */
|
||||||
|
typedef struct DVDNavParseContext {
|
||||||
|
uint32_t lba;
|
||||||
|
uint8_t buffer[PCI_SIZE+DSI_SIZE];
|
||||||
|
int copied;
|
||||||
|
} DVDNavParseContext;
|
||||||
|
|
||||||
|
static av_cold int dvd_nav_parse_init(AVCodecParserContext *s)
|
||||||
|
{
|
||||||
|
DVDNavParseContext *pc = s->priv_data;
|
||||||
|
|
||||||
|
pc->lba = 0xFFFFFFFF;
|
||||||
|
pc->copied = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dvd_nav_parse(AVCodecParserContext *s,
|
||||||
|
AVCodecContext *avctx,
|
||||||
|
const uint8_t **poutbuf, int *poutbuf_size,
|
||||||
|
const uint8_t *buf, int buf_size)
|
||||||
|
{
|
||||||
|
DVDNavParseContext *pc1 = s->priv_data;
|
||||||
|
int lastPacket = 0;
|
||||||
|
int valid = 0;
|
||||||
|
|
||||||
|
s->pict_type = AV_PICTURE_TYPE_NONE;
|
||||||
|
|
||||||
|
avctx->time_base.num = 1;
|
||||||
|
avctx->time_base.den = 90000;
|
||||||
|
|
||||||
|
if (buf && buf_size) {
|
||||||
|
switch(buf[0]) {
|
||||||
|
case 0x00:
|
||||||
|
if (buf_size == PCI_SIZE) {
|
||||||
|
/* PCI */
|
||||||
|
uint32_t lba = AV_RB32(&buf[0x01]);
|
||||||
|
uint32_t startpts = AV_RB32(&buf[0x0D]);
|
||||||
|
uint32_t endpts = AV_RB32(&buf[0x11]);
|
||||||
|
|
||||||
|
if (endpts > startpts) {
|
||||||
|
pc1->lba = lba;
|
||||||
|
s->pts = (int64_t)startpts;
|
||||||
|
s->duration = endpts - startpts;
|
||||||
|
|
||||||
|
memcpy(pc1->buffer, buf, PCI_SIZE);
|
||||||
|
pc1->copied = PCI_SIZE;
|
||||||
|
valid = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x01:
|
||||||
|
if ((buf_size == DSI_SIZE) && (pc1->copied == PCI_SIZE)) {
|
||||||
|
/* DSI */
|
||||||
|
uint32_t lba = AV_RB32(&buf[0x05]);
|
||||||
|
|
||||||
|
if (lba == pc1->lba) {
|
||||||
|
memcpy(pc1->buffer + pc1->copied, buf, DSI_SIZE);
|
||||||
|
lastPacket = 1;
|
||||||
|
valid = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid || lastPacket) {
|
||||||
|
pc1->copied = 0;
|
||||||
|
pc1->lba = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastPacket) {
|
||||||
|
*poutbuf = pc1->buffer;
|
||||||
|
*poutbuf_size = sizeof(pc1->buffer);
|
||||||
|
} else {
|
||||||
|
*poutbuf = NULL;
|
||||||
|
*poutbuf_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVCodecParser ff_dvd_nav_parser = {
|
||||||
|
.codec_ids = { AV_CODEC_ID_DVD_NAV },
|
||||||
|
.priv_data_size = sizeof(DVDNavParseContext),
|
||||||
|
.parser_init = dvd_nav_parse_init,
|
||||||
|
.parser_parse = dvd_nav_parse,
|
||||||
|
};
|
@ -29,7 +29,7 @@
|
|||||||
#include "libavutil/avutil.h"
|
#include "libavutil/avutil.h"
|
||||||
|
|
||||||
#define LIBAVCODEC_VERSION_MAJOR 55
|
#define LIBAVCODEC_VERSION_MAJOR 55
|
||||||
#define LIBAVCODEC_VERSION_MINOR 0
|
#define LIBAVCODEC_VERSION_MINOR 1
|
||||||
#define LIBAVCODEC_VERSION_MICRO 100
|
#define LIBAVCODEC_VERSION_MICRO 100
|
||||||
|
|
||||||
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include "libavutil/avassert.h"
|
||||||
|
|
||||||
/*********************************************/
|
/*********************************************/
|
||||||
/* demux code */
|
/* demux code */
|
||||||
@ -108,6 +109,7 @@ typedef struct MpegDemuxContext {
|
|||||||
int32_t header_state;
|
int32_t header_state;
|
||||||
unsigned char psm_es_type[256];
|
unsigned char psm_es_type[256];
|
||||||
int sofdec;
|
int sofdec;
|
||||||
|
int dvd;
|
||||||
#if CONFIG_VOBSUB_DEMUXER
|
#if CONFIG_VOBSUB_DEMUXER
|
||||||
AVFormatContext *sub_ctx;
|
AVFormatContext *sub_ctx;
|
||||||
FFDemuxSubtitlesQueue q;
|
FFDemuxSubtitlesQueue q;
|
||||||
@ -247,22 +249,83 @@ static int mpegps_read_pes_header(AVFormatContext *s,
|
|||||||
goto redo;
|
goto redo;
|
||||||
}
|
}
|
||||||
if (startcode == PRIVATE_STREAM_2) {
|
if (startcode == PRIVATE_STREAM_2) {
|
||||||
len = avio_rb16(s->pb);
|
|
||||||
if (!m->sofdec) {
|
if (!m->sofdec) {
|
||||||
while (len-- >= 6) {
|
/* Need to detect whether this from a DVD or a 'Sofdec' stream */
|
||||||
if (avio_r8(s->pb) == 'S') {
|
int len = avio_rb16(s->pb);
|
||||||
uint8_t buf[5];
|
int bytesread = 0;
|
||||||
avio_read(s->pb, buf, sizeof(buf));
|
uint8_t *ps2buf = av_malloc(len);
|
||||||
m->sofdec = !memcmp(buf, "ofdec", 5);
|
|
||||||
len -= sizeof(buf);
|
if (ps2buf) {
|
||||||
break;
|
bytesread = avio_read(s->pb, ps2buf, len);
|
||||||
}
|
|
||||||
}
|
if (bytesread != len) {
|
||||||
|
avio_skip(s->pb, len - bytesread);
|
||||||
|
} else {
|
||||||
|
uint8_t *p = 0;
|
||||||
|
if (len >= 6)
|
||||||
|
p = memchr(ps2buf, 'S', len - 5);
|
||||||
|
|
||||||
|
if (p)
|
||||||
|
m->sofdec = !memcmp(p+1, "ofdec", 5);
|
||||||
|
|
||||||
m->sofdec -= !m->sofdec;
|
m->sofdec -= !m->sofdec;
|
||||||
|
|
||||||
|
if (m->sofdec < 0) {
|
||||||
|
if (len == 980 && ps2buf[0] == 0) {
|
||||||
|
/* PCI structure? */
|
||||||
|
uint32_t startpts = AV_RB32(ps2buf + 0x0d);
|
||||||
|
uint32_t endpts = AV_RB32(ps2buf + 0x11);
|
||||||
|
uint8_t hours = ((ps2buf[0x19] >> 4) * 10) + (ps2buf[0x19] & 0x0f);
|
||||||
|
uint8_t mins = ((ps2buf[0x1a] >> 4) * 10) + (ps2buf[0x1a] & 0x0f);
|
||||||
|
uint8_t secs = ((ps2buf[0x1b] >> 4) * 10) + (ps2buf[0x1b] & 0x0f);
|
||||||
|
|
||||||
|
m->dvd = (hours <= 23 &&
|
||||||
|
mins <= 59 &&
|
||||||
|
secs <= 59 &&
|
||||||
|
(ps2buf[0x19] & 0x0f) < 10 &&
|
||||||
|
(ps2buf[0x1a] & 0x0f) < 10 &&
|
||||||
|
(ps2buf[0x1b] & 0x0f) < 10 &&
|
||||||
|
endpts >= startpts);
|
||||||
|
} else if (len == 1018 && ps2buf[0] == 1) {
|
||||||
|
/* DSI structure? */
|
||||||
|
uint8_t hours = ((ps2buf[0x1d] >> 4) * 10) + (ps2buf[0x1d] & 0x0f);
|
||||||
|
uint8_t mins = ((ps2buf[0x1e] >> 4) * 10) + (ps2buf[0x1e] & 0x0f);
|
||||||
|
uint8_t secs = ((ps2buf[0x1f] >> 4) * 10) + (ps2buf[0x1f] & 0x0f);
|
||||||
|
|
||||||
|
m->dvd = (hours <= 23 &&
|
||||||
|
mins <= 59 &&
|
||||||
|
secs <= 59 &&
|
||||||
|
(ps2buf[0x1d] & 0x0f) < 10 &&
|
||||||
|
(ps2buf[0x1e] & 0x0f) < 10 &&
|
||||||
|
(ps2buf[0x1f] & 0x0f) < 10);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
av_free(ps2buf);
|
||||||
|
|
||||||
|
/* If this isn't a DVD packet or no memory
|
||||||
|
* could be allocated, just ignore it.
|
||||||
|
* If we did, move back to the start of the
|
||||||
|
* packet (plus 'length' field) */
|
||||||
|
if (!m->dvd || avio_skip(s->pb, -(len + 2)) < 0) {
|
||||||
|
/* Skip back failed.
|
||||||
|
* This packet will be lost but that can't be helped
|
||||||
|
* if we can't skip back
|
||||||
|
*/
|
||||||
|
goto redo;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* No memory */
|
||||||
avio_skip(s->pb, len);
|
avio_skip(s->pb, len);
|
||||||
goto redo;
|
goto redo;
|
||||||
}
|
}
|
||||||
|
} else if (!m->dvd) {
|
||||||
|
int len = avio_rb16(s->pb);
|
||||||
|
avio_skip(s->pb, len);
|
||||||
|
goto redo;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (startcode == PROGRAM_STREAM_MAP) {
|
if (startcode == PROGRAM_STREAM_MAP) {
|
||||||
mpegps_psm_parse(m, s->pb);
|
mpegps_psm_parse(m, s->pb);
|
||||||
goto redo;
|
goto redo;
|
||||||
@ -271,7 +334,9 @@ static int mpegps_read_pes_header(AVFormatContext *s,
|
|||||||
/* find matching stream */
|
/* find matching stream */
|
||||||
if (!((startcode >= 0x1c0 && startcode <= 0x1df) ||
|
if (!((startcode >= 0x1c0 && startcode <= 0x1df) ||
|
||||||
(startcode >= 0x1e0 && startcode <= 0x1ef) ||
|
(startcode >= 0x1e0 && startcode <= 0x1ef) ||
|
||||||
(startcode == 0x1bd) || (startcode == 0x1fd)))
|
(startcode == 0x1bd) ||
|
||||||
|
(startcode == PRIVATE_STREAM_2) ||
|
||||||
|
(startcode == 0x1fd)))
|
||||||
goto redo;
|
goto redo;
|
||||||
if (ppos) {
|
if (ppos) {
|
||||||
*ppos = avio_tell(s->pb) - 4;
|
*ppos = avio_tell(s->pb) - 4;
|
||||||
@ -279,6 +344,8 @@ static int mpegps_read_pes_header(AVFormatContext *s,
|
|||||||
len = avio_rb16(s->pb);
|
len = avio_rb16(s->pb);
|
||||||
pts =
|
pts =
|
||||||
dts = AV_NOPTS_VALUE;
|
dts = AV_NOPTS_VALUE;
|
||||||
|
if (startcode != PRIVATE_STREAM_2)
|
||||||
|
{
|
||||||
/* stuffing */
|
/* stuffing */
|
||||||
for(;;) {
|
for(;;) {
|
||||||
if (len < 1)
|
if (len < 1)
|
||||||
@ -352,6 +419,7 @@ static int mpegps_read_pes_header(AVFormatContext *s,
|
|||||||
}
|
}
|
||||||
else if( c!= 0xf )
|
else if( c!= 0xf )
|
||||||
goto redo;
|
goto redo;
|
||||||
|
}
|
||||||
|
|
||||||
if (startcode == PRIVATE_STREAM_1) {
|
if (startcode == PRIVATE_STREAM_1) {
|
||||||
startcode = avio_r8(s->pb);
|
startcode = avio_r8(s->pb);
|
||||||
@ -448,6 +516,9 @@ static int mpegps_read_packet(AVFormatContext *s,
|
|||||||
else
|
else
|
||||||
request_probe= 1;
|
request_probe= 1;
|
||||||
type = AVMEDIA_TYPE_VIDEO;
|
type = AVMEDIA_TYPE_VIDEO;
|
||||||
|
} else if (startcode == PRIVATE_STREAM_2) {
|
||||||
|
type = AVMEDIA_TYPE_DATA;
|
||||||
|
codec_id = AV_CODEC_ID_DVD_NAV;
|
||||||
} else if (startcode >= 0x1c0 && startcode <= 0x1df) {
|
} else if (startcode >= 0x1c0 && startcode <= 0x1df) {
|
||||||
type = AVMEDIA_TYPE_AUDIO;
|
type = AVMEDIA_TYPE_AUDIO;
|
||||||
codec_id = m->sofdec > 0 ? AV_CODEC_ID_ADPCM_ADX : AV_CODEC_ID_MP2;
|
codec_id = m->sofdec > 0 ? AV_CODEC_ID_ADPCM_ADX : AV_CODEC_ID_MP2;
|
||||||
|
Loading…
Reference in New Issue
Block a user