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>tags/n2.0
@@ -743,6 +743,7 @@ OBJS-$(CONFIG_PNG_PARSER) += png_parser.o | |||
OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o \ | |||
mpegaudiodecheader.o mpegaudiodata.o | |||
OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \ | |||
dvd_nav_parser.o \ | |||
mpeg12.o mpeg12data.o | |||
OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o | |||
OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o | |||
@@ -515,6 +515,7 @@ void avcodec_register_all(void) | |||
REGISTER_PARSER(DNXHD, dnxhd); | |||
REGISTER_PARSER(DVBSUB, dvbsub); | |||
REGISTER_PARSER(DVDSUB, dvdsub); | |||
REGISTER_PARSER(DVD_NAV, dvd_nav); | |||
REGISTER_PARSER(FLAC, flac); | |||
REGISTER_PARSER(GSM, gsm); | |||
REGISTER_PARSER(H261, h261); | |||
@@ -482,6 +482,8 @@ enum AVCodecID { | |||
AV_CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'), | |||
AV_CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'), | |||
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 | |||
@@ -2525,6 +2525,12 @@ static const AVCodecDescriptor codec_descriptors[] = { | |||
.name = "klv", | |||
.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"), | |||
}, | |||
}; | |||
@@ -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" | |||
#define LIBAVCODEC_VERSION_MAJOR 55 | |||
#define LIBAVCODEC_VERSION_MINOR 0 | |||
#define LIBAVCODEC_VERSION_MINOR 1 | |||
#define LIBAVCODEC_VERSION_MICRO 100 | |||
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | |||
@@ -30,6 +30,7 @@ | |||
#undef NDEBUG | |||
#include <assert.h> | |||
#include "libavutil/avassert.h" | |||
/*********************************************/ | |||
/* demux code */ | |||
@@ -108,6 +109,7 @@ typedef struct MpegDemuxContext { | |||
int32_t header_state; | |||
unsigned char psm_es_type[256]; | |||
int sofdec; | |||
int dvd; | |||
#if CONFIG_VOBSUB_DEMUXER | |||
AVFormatContext *sub_ctx; | |||
FFDemuxSubtitlesQueue q; | |||
@@ -247,21 +249,82 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||
goto redo; | |||
} | |||
if (startcode == PRIVATE_STREAM_2) { | |||
len = avio_rb16(s->pb); | |||
if (!m->sofdec) { | |||
while (len-- >= 6) { | |||
if (avio_r8(s->pb) == 'S') { | |||
uint8_t buf[5]; | |||
avio_read(s->pb, buf, sizeof(buf)); | |||
m->sofdec = !memcmp(buf, "ofdec", 5); | |||
len -= sizeof(buf); | |||
break; | |||
/* Need to detect whether this from a DVD or a 'Sofdec' stream */ | |||
int len = avio_rb16(s->pb); | |||
int bytesread = 0; | |||
uint8_t *ps2buf = av_malloc(len); | |||
if (ps2buf) { | |||
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; | |||
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); | |||
goto redo; | |||
} | |||
m->sofdec -= !m->sofdec; | |||
} else if (!m->dvd) { | |||
int len = avio_rb16(s->pb); | |||
avio_skip(s->pb, len); | |||
goto redo; | |||
} | |||
avio_skip(s->pb, len); | |||
goto redo; | |||
} | |||
if (startcode == PROGRAM_STREAM_MAP) { | |||
mpegps_psm_parse(m, s->pb); | |||
@@ -271,7 +334,9 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||
/* find matching stream */ | |||
if (!((startcode >= 0x1c0 && startcode <= 0x1df) || | |||
(startcode >= 0x1e0 && startcode <= 0x1ef) || | |||
(startcode == 0x1bd) || (startcode == 0x1fd))) | |||
(startcode == 0x1bd) || | |||
(startcode == PRIVATE_STREAM_2) || | |||
(startcode == 0x1fd))) | |||
goto redo; | |||
if (ppos) { | |||
*ppos = avio_tell(s->pb) - 4; | |||
@@ -279,6 +344,8 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||
len = avio_rb16(s->pb); | |||
pts = | |||
dts = AV_NOPTS_VALUE; | |||
if (startcode != PRIVATE_STREAM_2) | |||
{ | |||
/* stuffing */ | |||
for(;;) { | |||
if (len < 1) | |||
@@ -352,6 +419,7 @@ static int mpegps_read_pes_header(AVFormatContext *s, | |||
} | |||
else if( c!= 0xf ) | |||
goto redo; | |||
} | |||
if (startcode == PRIVATE_STREAM_1) { | |||
startcode = avio_r8(s->pb); | |||
@@ -448,6 +516,9 @@ static int mpegps_read_packet(AVFormatContext *s, | |||
else | |||
request_probe= 1; | |||
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) { | |||
type = AVMEDIA_TYPE_AUDIO; | |||
codec_id = m->sofdec > 0 ? AV_CODEC_ID_ADPCM_ADX : AV_CODEC_ID_MP2; | |||