diff options
Diffstat (limited to 'demux')
-rw-r--r-- | demux/demux.c | 178 | ||||
-rw-r--r-- | demux/demux.h | 28 | ||||
-rw-r--r-- | demux/demux_mng.c | 15 | ||||
-rw-r--r-- | demux/demux_rawvideo.c | 1 |
4 files changed, 70 insertions, 152 deletions
diff --git a/demux/demux.c b/demux/demux.c index f0cb28ab1d..16adfeb795 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -375,26 +375,16 @@ int demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream, void ds_add_packet(demux_stream_t *ds, demux_packet_t *dp) { - // demux API can't handle 0-sized packets, but at least some vobsubs - // generate them. Skipping them seems to work fine. Not skipping them will - // stop demuxing with external vobsubs. See FATE sub/vobsub.{idx,sub} at - // pts=185.91. - if (dp->len == 0 && ds->stream_type == STREAM_SUB) { - mp_dbg(MSGT_DEMUXER, MSGL_INFO, "Discarding empty subtitle packet.\n"); - free_demux_packet(dp); - return; - } - // append packet to DS stream: ++ds->packs; ds->bytes += dp->len; - if (ds->last) { + if (ds->tail) { // next packet in stream - ds->last->next = dp; - ds->last = dp; + ds->tail->next = dp; + ds->tail = dp; } else { // first packet in stream - ds->first = ds->last = dp; + ds->head = ds->tail = dp; } mp_dbg(MSGT_DEMUXER, MSGL_DBG2, "DEMUX: Append packet to %s, len=%d pts=%5.3f pos=%u [packs: A=%d V=%d]\n", @@ -440,38 +430,18 @@ int demux_fill_buffer(demuxer_t *demux, demux_stream_t *ds) // return value: // 0 = EOF // 1 = successful -int ds_fill_buffer(demux_stream_t *ds) +static int ds_get_packets(demux_stream_t *ds) { + if (!ds) + return 0; demuxer_t *demux = ds->demuxer; - if (ds->current) - free_demux_packet(ds->current); - ds->current = NULL; - mp_dbg(MSGT_DEMUXER, MSGL_DBG3, "ds_fill_buffer (%s) called\n", + mp_dbg(MSGT_DEMUXER, MSGL_DBG3, "ds_get_packets (%s) called\n", ds == demux->audio ? "d_audio" : ds == demux->video ? "d_video" : ds == demux->sub ? "d_sub" : "unknown"); while (1) { int apacks = demux->audio ? demux->audio->packs : 0; int vpacks = demux->video ? demux->video->packs : 0; if (ds->packs) { - demux_packet_t *p = ds->first; - // copy useful data: - ds->buffer = p->buffer; - ds->buffer_pos = 0; - ds->buffer_size = p->len; - if (p->pts != MP_NOPTS_VALUE) { - ds->pts = p->pts; - ds->pts_bytes = 0; - } - ds->pts_bytes += p->len; // !!! - if (p->stream_pts != MP_NOPTS_VALUE) - demux->stream_pts = p->stream_pts; - // unlink packet: - ds->bytes -= p->len; - ds->current = p; - ds->first = p->next; - if (!ds->first) - ds->last = NULL; - --ds->packs; /* The code below can set ds->eof to 1 when another stream runs * out of buffer space. That makes sense because in that situation * the calling code should not count on being able to demux more @@ -497,7 +467,7 @@ int ds_fill_buffer(demux_stream_t *ds) if (!demux_fill_buffer(demux, ds)) { mp_dbg(MSGT_DEMUXER, MSGL_DBG2, - "ds_fill_buffer()->demux_fill_buffer() failed\n"); + "ds_get_packets()->demux_fill_buffer() failed\n"); break; // EOF } @@ -508,10 +478,8 @@ int ds_fill_buffer(demux_stream_t *ds) ds->fill_count++; } } - ds->buffer_pos = ds->buffer_size = 0; - ds->buffer = NULL; mp_msg(MSGT_DEMUXER, MSGL_V, - "ds_fill_buffer: EOF reached (stream: %s) \n", + "ds_get_packets: EOF reached (stream: %s) \n", ds == demux->audio ? "audio" : "video"); ds->eof = 1; return 0; @@ -519,100 +487,76 @@ int ds_fill_buffer(demux_stream_t *ds) void ds_free_packs(demux_stream_t *ds) { - demux_packet_t *dp = ds->first; + demux_packet_t *dp = ds->head; while (dp) { demux_packet_t *dn = dp->next; free_demux_packet(dp); dp = dn; } - ds->first = ds->last = NULL; + ds->head = ds->tail = NULL; ds->packs = 0; // !!!!! ds->bytes = 0; - if (ds->current) - free_demux_packet(ds->current); - ds->current = NULL; - ds->buffer = NULL; - ds->buffer_pos = ds->buffer_size; - ds->pts = MP_NOPTS_VALUE; - ds->pts_bytes = 0; -} - -int ds_get_packet(demux_stream_t *ds, unsigned char **start) -{ - int len; - if (ds->buffer_pos >= ds->buffer_size) { - if (!ds_fill_buffer(ds)) { - // EOF - *start = NULL; - return -1; - } - } - len = ds->buffer_size - ds->buffer_pos; - *start = &ds->buffer[ds->buffer_pos]; - ds->buffer_pos += len; - return len; + ds->last_pts = MP_NOPTS_VALUE; + ds->last_pts_bytes = 0; } -int ds_get_packet_pts(demux_stream_t *ds, unsigned char **start, double *pts) +static struct demux_stream *ds_from_sh(struct sh_stream *sh) { - int len; - *pts = MP_NOPTS_VALUE; - len = ds_get_packet(ds, start); - if (len < 0) - return len; - // Return pts unless this read starts from the middle of a packet - if (len == ds->buffer_pos) - *pts = ds->current->pts; - return len; + for (int n = 0; n < STREAM_TYPE_COUNT; n++) { + if (sh->demuxer->ds[n]->gsh == sh) + return sh->demuxer->ds[n]; + } + return NULL; } -struct demux_packet *ds_get_packet_sub(demux_stream_t *ds) -{ - if (ds->buffer_pos >= ds->buffer_size) { - if (!ds->packs) - return NULL; // no sub - if (!ds_fill_buffer(ds)) - return NULL; // EOF - } - if (ds->buffer_pos < ds->buffer_size) { - ds->current->buffer += ds->buffer_pos; - ds->buffer_size -= ds->buffer_pos; +// Read a packet from the given stream. The returned packet belongs to the +// caller, who has to free it with talloc_free(). Might block. Returns NULL +// on EOF. +struct demux_packet *demux_read_packet(struct sh_stream *sh) +{ + struct demux_stream *ds = ds_from_sh(sh); + if (ds) { + ds_get_packets(ds); + struct demux_packet *pkt = ds->head; + if (pkt) { + ds->head = pkt->next; + pkt->next = NULL; + if (!ds->head) + ds->tail = NULL; + ds->bytes -= pkt->len; + ds->packs--; + + if (pkt->pts != MP_NOPTS_VALUE) { + ds->last_pts = pkt->pts; + ds->last_pts_bytes = 0; + } else { + ds->last_pts_bytes += pkt->len; + } + + if (pkt->stream_pts != MP_NOPTS_VALUE) + sh->demuxer->stream_pts = pkt->stream_pts; + + return pkt; + } } - ds->buffer_pos = ds->buffer_size; - return ds->current; + return NULL; } -struct demux_packet *ds_get_packet2(struct demux_stream *ds, bool repeat_last) +// Return the pts of the next packet that demux_read_packet() would return. +// Might block. Sometimes used to force a packet read, without removing any +// packets from the queue. +double demux_get_next_pts(struct sh_stream *sh) { - if (!repeat_last) - ds_fill_buffer(ds); - // This shouldn't get used together with partial reads - // However, some old demuxers return parsed packets with an offset in - // -correct-pts mode (at least mpegts). - // Not all old demuxers will actually work. - if (ds->buffer_pos < ds->buffer_size) { - ds->current->buffer += ds->buffer_pos; - ds->buffer_size -= ds->buffer_pos; - } - ds->buffer_pos = ds->buffer_size; - return ds->current; + struct demux_stream *ds = ds_from_sh(sh); + ds_get_packets(ds); + return ds && ds->head ? ds->head->pts : MP_NOPTS_VALUE; } -double ds_get_next_pts(demux_stream_t *ds) +// Return whether a packet is queued. Never blocks, never forces any reads. +bool demux_has_packet(struct sh_stream *sh) { - demuxer_t *demux = ds->demuxer; - // if we have not read from the "current" packet, consider it - // as the next, otherwise we never get the pts for the first packet. - while (!ds->first && (!ds->current || ds->buffer_pos)) { - if (demux_check_queue_full(demux)) - return MP_NOPTS_VALUE; - if (!demux_fill_buffer(demux, ds)) - return MP_NOPTS_VALUE; - } - // take pts from "current" if we never read from it. - if (ds->current && !ds->buffer_pos) - return ds->current->pts; - return ds->first->pts; + struct demux_stream *ds = ds_from_sh(sh); + return ds && ds->head; } // ==================================================================== diff --git a/demux/demux.h b/demux/demux.h index eb5de265b3..fade7533e9 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -90,19 +90,15 @@ enum timestamp_type { typedef struct demux_stream { enum stream_type stream_type; - int buffer_pos; // current buffer position - int buffer_size; // current buffer size - unsigned char *buffer; // current buffer, never free() it, always use free_demux_packet(buffer_ref); - double pts; // current buffer's pts - int pts_bytes; // number of bytes read after last pts stamp + double last_pts; // pts of the last packet that was read + int last_pts_bytes; // number of bytes read after last pts stamp int eof; // end of demuxed stream? (true if all buffer empty) //--------------- int fill_count; // number of unsuccessful tries to get a packet int packs; // number of packets in buffer int bytes; // total bytes of packets in buffer - demux_packet_t *first; // read to current buffer from here - demux_packet_t *last; // append new packets from input stream to here - demux_packet_t *current; // needed for refcounting of the buffer + struct demux_packet *head; + struct demux_packet *tail; struct demuxer *demuxer; // parent demuxer structure (stream handler) // ---- stream header ---- struct sh_stream *gsh; @@ -256,20 +252,12 @@ int demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream, void ds_add_packet(struct demux_stream *ds, struct demux_packet *dp); int demux_fill_buffer(struct demuxer *demux, struct demux_stream *ds); -int ds_fill_buffer(struct demux_stream *ds); - -static inline int ds_tell_pts(struct demux_stream *ds) -{ - return (ds->pts_bytes - ds->buffer_size) + ds->buffer_pos; -} void ds_free_packs(struct demux_stream *ds); -int ds_get_packet(struct demux_stream *ds, unsigned char **start); -int ds_get_packet_pts(struct demux_stream *ds, unsigned char **start, - double *pts); -struct demux_packet *ds_get_packet_sub(demux_stream_t *ds); -struct demux_packet *ds_get_packet2(struct demux_stream *ds, bool repeat_last); -double ds_get_next_pts(struct demux_stream *ds); + +struct demux_packet *demux_read_packet(struct sh_stream *sh); +double demux_get_next_pts(struct sh_stream *sh); +bool demux_has_packet(struct sh_stream *sh); struct demuxer *demux_open(struct MPOpts *opts, struct stream *stream, int file_format, char *filename); diff --git a/demux/demux_mng.c b/demux/demux_mng.c index 76b742f019..6dc0e352e8 100644 --- a/demux/demux_mng.c +++ b/demux/demux_mng.c @@ -38,14 +38,6 @@ #include <libmng.h> /** - * \brief some small fixed start time > 0 - * - * Start time must be > 0 for the variable frame time mechanism - * (GIF, MATROSKA, MNG) in video.c to work for the first frame. - */ -#define MNG_START_PTS 0.01f - -/** * \brief private context structure * * This structure is used as private data for MPlayer demuxer @@ -346,7 +338,7 @@ static int demux_mng_fill_buffer(demuxer_t * demuxer, // Set position and timing information in demuxer video and demuxer packet. // - Time must be time of next frame and always be > 0 for the variable // frame time mechanism (GIF, MATROSKA, MNG) in video.c to work. - dp->pts = (float)mng_priv->show_next_time_ms / 1000.0f + MNG_START_PTS; + dp->pts = (float)mng_priv->show_next_time_ms / 1000.0f; dp->pos = stream_tell(demuxer->stream); ds_add_packet(demuxer->video, dp); @@ -447,11 +439,6 @@ static demuxer_t * demux_mng_open(demuxer_t * demuxer) sh_video->bih->biBitCount = 32; sh_video->bih->biPlanes = 1; - // Set start time to something > 0. - // - This is required for the variable frame time mechanism - // (GIF, MATROSKA, MNG) in video.c to work for the first frame. - sh_video->ds->pts = MNG_START_PTS; - // set private data in demuxer and return demuxer demuxer->priv = mng_priv; return demuxer; diff --git a/demux/demux_rawvideo.c b/demux/demux_rawvideo.c index a4eaaa2a8c..787bd0c064 100644 --- a/demux/demux_rawvideo.c +++ b/demux/demux_rawvideo.c @@ -164,7 +164,6 @@ static void demux_rawvideo_seek(demuxer_t *demuxer,float rel_seek_secs,float aud pos/=imgsize; stream_seek(s,pos*imgsize); //sh_video->timer=pos * sh_video->frametime; - demuxer->video->pts = pos * sh_video->frametime; // printf("demux_rawvideo: streamtell=%d\n",(int)stream_tell(demuxer->stream)); } |