/*
- * MPEG1/2 mux/demux
+ * MPEG1/2 muxer and demuxer
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard.
*
- * This library is free software; you can redistribute it and/or
+ * 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 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * 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 this library; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
#include "bitstream.h"
+#include "fifo.h"
#define MAX_PAYLOAD_SIZE 4096
//#define DEBUG_SEEK
} PacketDesc;
typedef struct {
- FifoBuffer fifo;
+ AVFifoBuffer fifo;
uint8_t id;
int max_buffer_size; /* in bytes */
int buffer_index;
int packet_number;
uint8_t lpcm_header[3];
int lpcm_align;
- uint8_t *fifo_iframe_ptr;
+ int bytes_to_iframe;
int align_iframe;
int64_t vobu_start_pts;
} StreamInfo;
default:
return -1;
}
- fifo_init(&stream->fifo, 16);
+ av_fifo_init(&stream->fifo, 16);
}
bitrate = 0;
audio_bitrate = 0;
for(i=0;i<ctx->nb_streams;i++) {
av_free(ctx->streams[i]->priv_data);
}
- return -ENOMEM;
+ return AVERROR(ENOMEM);
}
static inline void put_timestamp(ByteIOContext *pb, int id, int64_t timestamp)
}
} else if (s->is_dvd) {
if (stream->align_iframe || s->packet_number == 0){
- int bytes_to_iframe;
- int PES_bytes_to_fill;
- if (stream->fifo_iframe_ptr >= stream->fifo.rptr) {
- bytes_to_iframe = stream->fifo_iframe_ptr - stream->fifo.rptr;
- } else {
- bytes_to_iframe = (stream->fifo.end - stream->fifo.rptr) + (stream->fifo_iframe_ptr - stream->fifo.buffer);
- }
- PES_bytes_to_fill = s->packet_size - size - 10;
+ int PES_bytes_to_fill = s->packet_size - size - 10;
if (pts != AV_NOPTS_VALUE) {
if (dts != pts)
PES_bytes_to_fill -= 5;
}
- if (bytes_to_iframe == 0 || s->packet_number == 0) {
+ if (stream->bytes_to_iframe == 0 || s->packet_number == 0) {
size = put_system_header(ctx, buf_ptr, 0);
buf_ptr += size;
size = buf_ptr - buffer;
s->last_scr= scr;
buf_ptr += size;
/* GOP Start */
- } else if (bytes_to_iframe < PES_bytes_to_fill) {
- pad_packet_bytes = PES_bytes_to_fill - bytes_to_iframe;
+ } else if (stream->bytes_to_iframe < PES_bytes_to_fill) {
+ pad_packet_bytes = PES_bytes_to_fill - stream->bytes_to_iframe;
}
}
} else {
startcode = 0x100 + id;
}
- stuffing_size = payload_size - fifo_size(&stream->fifo, stream->fifo.rptr);
+ stuffing_size = payload_size - av_fifo_size(&stream->fifo);
// first byte doesnt fit -> reset pts/dts + stuffing
if(payload_size <= trailer_size && pts != AV_NOPTS_VALUE){
}
/* output data */
- if(put_fifo(&ctx->pb, &stream->fifo, payload_size - stuffing_size, &stream->fifo.rptr) < 0)
+ if(av_fifo_generic_read(&stream->fifo, payload_size - stuffing_size, &put_buffer, &ctx->pb) < 0)
return -1;
+ stream->bytes_to_iframe -= payload_size - stuffing_size;
}else{
payload_size=
stuffing_size= 0;
for(i=0; i<ctx->nb_streams; i++){
AVStream *st = ctx->streams[i];
StreamInfo *stream = st->priv_data;
- const int avail_data= fifo_size(&stream->fifo, stream->fifo.rptr);
+ const int avail_data= av_fifo_size(&stream->fifo);
const int space= stream->max_buffer_size - stream->buffer_index;
int rel_space= 1024*space / stream->max_buffer_size;
PacketDesc *next_pkt= stream->premux_packet;
st = ctx->streams[best_i];
stream = st->priv_data;
- assert(fifo_size(&stream->fifo, stream->fifo.rptr) > 0);
+ assert(av_fifo_size(&stream->fifo) > 0);
assert(avail_space >= s->packet_size || ignore_constraints);
//av_log(ctx, AV_LOG_DEBUG, "dts:%f pts:%f scr:%f stream:%d\n", timestamp_packet->dts/90000.0, timestamp_packet->pts/90000.0, scr/90000.0, best_i);
es_size= flush_packet(ctx, best_i, timestamp_packet->pts, timestamp_packet->dts, scr, trailer_size);
}else{
- assert(fifo_size(&stream->fifo, stream->fifo.rptr) == trailer_size);
+ assert(av_fifo_size(&stream->fifo) == trailer_size);
es_size= flush_packet(ctx, best_i, AV_NOPTS_VALUE, AV_NOPTS_VALUE, scr, trailer_size);
}
stream->predecode_packet= pkt_desc;
stream->next_packet= &pkt_desc->next;
- fifo_realloc(&stream->fifo, fifo_size(&stream->fifo, NULL) + size + 1);
+ av_fifo_realloc(&stream->fifo, av_fifo_size(&stream->fifo) + size + 1);
if (s->is_dvd){
if (is_iframe && (s->packet_number == 0 || (pts - stream->vobu_start_pts >= 36000))) { // min VOBU length 0.4 seconds (mpucoder)
- stream->fifo_iframe_ptr = stream->fifo.wptr;
+ stream->bytes_to_iframe = av_fifo_size(&stream->fifo);
stream->align_iframe = 1;
stream->vobu_start_pts = pts;
} else {
}
}
- fifo_write(&stream->fifo, buf, size, &stream->fifo.wptr);
+ av_fifo_write(&stream->fifo, buf, size);
for(;;){
int ret= output_packet(ctx, 0);
for(i=0;i<ctx->nb_streams;i++) {
stream = ctx->streams[i]->priv_data;
- assert(fifo_size(&stream->fifo, stream->fifo.rptr) == 0);
- fifo_free(&stream->fifo);
+ assert(av_fifo_size(&stream->fifo) == 0);
+ av_fifo_free(&stream->fifo);
}
return 0;
}
#define MAX_SYNC_SIZE 100000
+static int cdxa_probe(AVProbeData *p)
+{
+ /* check file header */
+ if (p->buf[0] == 'R' && p->buf[1] == 'I' &&
+ p->buf[2] == 'F' && p->buf[3] == 'F' &&
+ p->buf[8] == 'C' && p->buf[9] == 'D' &&
+ p->buf[10] == 'X' && p->buf[11] == 'A')
+ return AVPROBE_SCORE_MAX;
+ else
+ return 0;
+}
+
static int mpegps_probe(AVProbeData *p)
{
uint32_t code= -1;
int i;
int score=0;
+ score = cdxa_probe(p);
+ if (score > 0) return score;
+
+ /* Search for MPEG stream */
for(i=0; i<p->buf_size; i++){
code = (code<<8) + p->buf[i];
if ((code & 0xffffff00) == 0x100) {
typedef struct MpegDemuxContext {
- int header_state;
+ int32_t header_state;
unsigned char psm_es_type[256];
} MpegDemuxContext;
}
static int find_next_start_code(ByteIOContext *pb, int *size_ptr,
- uint32_t *header_state)
+ int32_t *header_state)
{
unsigned int state, v;
int val, n;
{
MpegDemuxContext *m = s->priv_data;
int len, size, startcode, c, flags, header_len;
- int64_t pts, dts, last_pos;
+ int pes_ext, ext2_len, id_ext, skip;
+ int64_t pts, dts;
+ int64_t last_sync= url_ftell(&s->pb);
- last_pos = -1;
+ error_redo:
+ url_fseek(&s->pb, last_sync, SEEK_SET);
redo:
/* next start code (should be immediately after) */
m->header_state = 0xff;
size = MAX_SYNC_SIZE;
startcode = find_next_start_code(&s->pb, &size, &m->header_state);
- //printf("startcode=%x pos=0x%Lx\n", startcode, url_ftell(&s->pb));
+ last_sync = url_ftell(&s->pb);
+ //printf("startcode=%x pos=0x%"PRIx64"\n", startcode, url_ftell(&s->pb));
if (startcode < 0)
return AVERROR_IO;
if (startcode == PACK_START_CODE)
/* find matching stream */
if (!((startcode >= 0x1c0 && startcode <= 0x1df) ||
(startcode >= 0x1e0 && startcode <= 0x1ef) ||
- (startcode == 0x1bd)))
+ (startcode == 0x1bd) || (startcode == 0x1fd)))
goto redo;
if (ppos) {
*ppos = url_ftell(&s->pb) - 4;
}
len = get_be16(&s->pb);
- pts = AV_NOPTS_VALUE;
+ pts =
dts = AV_NOPTS_VALUE;
/* stuffing */
for(;;) {
if (len < 1)
- goto redo;
+ goto error_redo;
c = get_byte(&s->pb);
len--;
/* XXX: for mpeg1, should test only bit 7 */
}
if ((c & 0xc0) == 0x40) {
/* buffer scale & size */
- if (len < 2)
- goto redo;
get_byte(&s->pb);
c = get_byte(&s->pb);
len -= 2;
}
- if ((c & 0xf0) == 0x20) {
- if (len < 4)
- goto redo;
+ if ((c & 0xe0) == 0x20) {
dts = pts = get_pts(&s->pb, c);
len -= 4;
- } else if ((c & 0xf0) == 0x30) {
- if (len < 9)
- goto redo;
- pts = get_pts(&s->pb, c);
- dts = get_pts(&s->pb, -1);
- len -= 9;
+ if (c & 0x10){
+ dts = get_pts(&s->pb, -1);
+ len -= 5;
+ }
} else if ((c & 0xc0) == 0x80) {
/* mpeg 2 PES */
#if 0 /* some streams have this field set for no apparent reason */
header_len = get_byte(&s->pb);
len -= 2;
if (header_len > len)
- goto redo;
- if ((flags & 0xc0) == 0x80) {
+ goto error_redo;
+ len -= header_len;
+ if (flags & 0x80) {
dts = pts = get_pts(&s->pb, -1);
- if (header_len < 5)
- goto redo;
header_len -= 5;
- len -= 5;
- } if ((flags & 0xc0) == 0xc0) {
- pts = get_pts(&s->pb, -1);
- dts = get_pts(&s->pb, -1);
- if (header_len < 10)
- goto redo;
- header_len -= 10;
- len -= 10;
+ if (flags & 0x40) {
+ dts = get_pts(&s->pb, -1);
+ header_len -= 5;
+ }
}
- len -= header_len;
- while (header_len > 0) {
- get_byte(&s->pb);
+ if (flags & 0x01) { /* PES extension */
+ pes_ext = get_byte(&s->pb);
header_len--;
+ if (pes_ext & 0x40) { /* pack header - should be zero in PS */
+ goto error_redo;
+ }
+ /* Skip PES private data, program packet sequence counter and P-STD buffer */
+ skip = (pes_ext >> 4) & 0xb;
+ skip += skip & 0x9;
+ url_fskip(&s->pb, skip);
+ header_len -= skip;
+
+ if (pes_ext & 0x01) { /* PES extension 2 */
+ ext2_len = get_byte(&s->pb);
+ header_len--;
+ if ((ext2_len & 0x7f) > 0) {
+ id_ext = get_byte(&s->pb);
+ if ((id_ext & 0x80) == 0)
+ startcode = ((startcode & 0xff) << 8) | id_ext;
+ header_len--;
+ }
+ }
}
+ if(header_len < 0)
+ goto error_redo;
+ url_fskip(&s->pb, header_len);
}
else if( c!= 0xf )
goto redo;
if (startcode == PRIVATE_STREAM_1 && !m->psm_es_type[startcode & 0xff]) {
- if (len < 1)
- goto redo;
startcode = get_byte(&s->pb);
len--;
- if (startcode >= 0x80 && startcode <= 0xbf) {
+ if (startcode >= 0x80 && startcode <= 0xcf) {
/* audio: skip header */
- if (len < 3)
- goto redo;
get_byte(&s->pb);
get_byte(&s->pb);
get_byte(&s->pb);
len -= 3;
+ if (startcode >= 0xb0 && startcode <= 0xbf) {
+ /* MLP/TrueHD audio has a 4-byte header */
+ get_byte(&s->pb);
+ len--;
+ }
}
}
+ if(len<0)
+ goto error_redo;
if(dts != AV_NOPTS_VALUE && ppos){
int i;
for(i=0; i<s->nb_streams; i++){
} else if (startcode >= 0x80 && startcode <= 0x87) {
type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_AC3;
- } else if (startcode >= 0x88 && startcode <= 0x9f) {
+ } else if ((startcode >= 0x88 && startcode <= 0x8f)
+ ||( startcode >= 0x98 && startcode <= 0x9f)) {
+ /* 0x90 - 0x97 is reserved for SDDS in DVD specs */
type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_DTS;
- } else if (startcode >= 0xa0 && startcode <= 0xbf) {
+ } else if (startcode >= 0xa0 && startcode <= 0xaf) {
type = CODEC_TYPE_AUDIO;
codec_id = CODEC_ID_PCM_S16BE;
+ } else if (startcode >= 0xb0 && startcode <= 0xbf) {
+ type = CODEC_TYPE_AUDIO;
+ codec_id = CODEC_ID_MLP;
+ } else if (startcode >= 0xc0 && startcode <= 0xcf) {
+ /* Used for both AC-3 and E-AC-3 in EVOB files */
+ type = CODEC_TYPE_AUDIO;
+ codec_id = CODEC_ID_AC3;
} else if (startcode >= 0x20 && startcode <= 0x3f) {
type = CODEC_TYPE_SUBTITLE;
codec_id = CODEC_ID_DVD_SUBTITLE;
+ } else if (startcode >= 0xfd55 && startcode <= 0xfd5f) {
+ type = CODEC_TYPE_VIDEO;
+ codec_id = CODEC_ID_VC1;
} else {
skip:
/* skip packet */
found:
if(st->discard >= AVDISCARD_ALL)
goto skip;
- if (startcode >= 0xa0 && startcode <= 0xbf) {
+ if (startcode >= 0xa0 && startcode <= 0xaf) {
int b1, freq;
/* for LPCM, we just skip the header and consider it is raw
pos = *ppos;
#ifdef DEBUG_SEEK
- printf("read_dts: pos=0x%llx next=%d -> ", pos, find_next);
+ printf("read_dts: pos=0x%"PRIx64" next=%d -> ", pos, find_next);
#endif
url_fseek(&s->pb, pos, SEEK_SET);
for(;;) {
url_fskip(&s->pb, len);
}
#ifdef DEBUG_SEEK
- printf("pos=0x%llx dts=0x%llx %0.3f\n", pos, dts, dts / 90000.0);
+ printf("pos=0x%"PRIx64" dts=0x%"PRIx64" %0.3f\n", pos, dts, dts / 90000.0);
#endif
*ppos = pos;
return dts;