1
mirror of https://github.com/mpv-player/mpv synced 2024-10-14 11:54:36 +02:00

Added support for MPEG-1 and MPEG-2 in Matroska.

git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@14055 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
mosu 2004-11-26 16:36:03 +00:00
parent abe3681629
commit 2f83863883
2 changed files with 137 additions and 4 deletions

View File

@ -92,6 +92,13 @@ typedef struct mkv_track
int subtitle_type;
/* The timecodes of video frames might have to be reordered if they're
in display order (the timecodes, not the frames themselves!). In this
case demux packets have to be cached with the help of these variables. */
int reorder_timecodes;
demux_packet_t **cached_dps;
int num_cached_dps, num_allocated_dps;
/* generic content encoding support */
mkv_content_encoding_t *encodings;
int num_encodings;
@ -429,6 +436,33 @@ vobsub_parse_forced_subs (mkv_track_t *t, const char *start)
return 8;
}
/** \brief Free cached demux packets
*
* Reordering the timecodes requires caching of demux packets. This function
* frees all these cached packets and the memory for the cached pointers
* itself.
*
* \param demuxer The demuxer for which the cache is to be freed.
*/
static void
free_cached_dps (demuxer_t *demuxer)
{
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
mkv_track_t *track;
int i, k;
for (k = 0; k < mkv_d->num_tracks; k++)
{
track = mkv_d->tracks[k];
for (i = 0; i < track->num_cached_dps; i++)
free_demux_packet (track->cached_dps[i]);
free(track->cached_dps);
track->cached_dps = NULL;
track->num_cached_dps = 0;
track->num_allocated_dps = 0;
}
}
static int
demux_mkv_parse_idx (mkv_track_t *t)
{
@ -1626,6 +1660,16 @@ demux_mkv_open_video (demuxer_t *demuxer, mkv_track_t *track)
#endif /* USE_QTX_CODECS */
}
else if (!strcmp(track->codec_id, MKV_V_MPEG1))
{
bih->biCompression = mmioFOURCC('m', 'p', 'g', '1');
track->reorder_timecodes = 1;
}
else if (!strcmp(track->codec_id, MKV_V_MPEG2))
{
bih->biCompression = mmioFOURCC('m', 'p', 'g', '2');
track->reorder_timecodes = 1;
}
else
{
mp_msg (MSGT_DEMUX,MSGL_WARN,"[mkv] Unknown/unsupported CodecID "
@ -2344,6 +2388,7 @@ demux_close_mkv (demuxer_t *demuxer)
if (mkv_d)
{
int i;
free_cached_dps (demuxer);
if (mkv_d->tracks)
{
for (i=0; i<mkv_d->num_tracks; i++)
@ -2739,9 +2784,89 @@ handle_realaudio (demuxer_t *demuxer, mkv_track_t *track, uint8_t *buffer,
ds_add_packet (demuxer->audio, dp);
}
/** Reorder timecodes and add cached demux packets to the queues.
*
* Timecode reordering is needed if a video track contains B frames that
* are timestamped in display order (e.g. MPEG-1, MPEG-2 or "native" MPEG-4).
* MPlayer doesn't like timestamps in display order. This function adjusts
* the timestamp of cached frames (which are exactly one I/P frame followed
* by one or more B frames) so that they are in coding order again.
*
* Example: The track with 25 FPS contains four frames with the timecodes
* I at 0ms, P at 120ms, B at 40ms and B at 80ms. As soon as the next I
* or P frame arrives these timecodes can be changed to I at 0ms, P at 40ms,
* B at 80ms and B at 120ms.
*
* \param demuxer The Matroska demuxer struct for this instance.
* \param track The track structure whose cache should be handled.
*/
static void
flush_cached_dps (demuxer_t *demuxer, mkv_track_t *track)
{
float tmp_pts;
int i;
if (track->num_cached_dps == 0)
return;
tmp_pts = track->cached_dps[0]->pts;
for (i = 1; i < track->num_cached_dps; i++)
track->cached_dps[i - 1]->pts = track->cached_dps[i]->pts;
track->cached_dps[track->num_cached_dps - 1]->pts = tmp_pts;
for (i = 0; i < track->num_cached_dps; i++)
ds_add_packet (demuxer->video, track->cached_dps[i]);
track->num_cached_dps = 0;
}
/** Cache video frames if timecodes have to be reordered.
*
* Timecode reordering is needed if a video track contains B frames that
* are timestamped in display order (e.g. MPEG-1, MPEG-2 or "native" MPEG-4).
* This function takes in a Matroska block read from the file, allocates a
* demux packet for it, fills in its values, allocates space for storing
* pointers to the cached demux packets and adds the packet to it. If
* the packet contains an I or a P frame then ::flush_cached_dps is called
* in order to send the old cached frames downstream.
*
* \param demuxer The Matroska demuxer struct for this instance.
* \param track The packet is meant for this track.
* \param buffer The actual frame contents.
* \param size The frame size in bytes.
* \param block_bref A relative timecode (backward reference). If it is \c 0
* then the frame is an I frame.
* \param block_fref A relative timecode (forward reference). If it is \c 0
* then the frame is either an I frame or a P frame depending on the value
* of \a block_bref. Otherwise it's a B frame.
*/
static void
handle_video_bframes (demuxer_t *demuxer, mkv_track_t *track, uint8_t *buffer,
uint32_t size, int block_bref, int block_fref)
{
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
demux_packet_t *dp;
dp = new_demux_packet (size);
memcpy(dp->buffer, buffer, size);
dp->pos = demuxer->filepos;
dp->pts = mkv_d->last_pts;
if (block_fref == 0) /* I or P frame */
flush_cached_dps (demuxer, track);
if (block_bref != 0) /* I frame, don't cache it */
dp->flags = 0x10;
if ((track->num_cached_dps + 1) > track->num_allocated_dps)
{
track->cached_dps = (demux_packet_t **)
realloc(track->cached_dps, (track->num_cached_dps + 10) *
sizeof(demux_packet_t *));
track->num_allocated_dps += 10;
}
track->cached_dps[track->num_cached_dps] = dp;
track->num_cached_dps++;
}
static int
handle_block (demuxer_t *demuxer, uint8_t *block, uint64_t length,
uint64_t block_duration, int64_t block_bref)
uint64_t block_duration, int64_t block_bref, int64_t block_fref)
{
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
mkv_track_t *track = NULL;
@ -2847,6 +2972,9 @@ handle_block (demuxer_t *demuxer, uint8_t *block, uint64_t length,
handle_realvideo (demuxer, track, block, lace_size[i], block_bref);
else if (ds == demuxer->audio && track->realmedia)
handle_realaudio (demuxer, track, block, lace_size[i], block_bref);
else if (ds == demuxer->video && track->reorder_timecodes)
handle_video_bframes (demuxer, track, block, lace_size[i],
block_bref, block_fref);
else
{
int modified, size = lace_size[i];
@ -2896,7 +3024,7 @@ demux_mkv_fill_buffer (demuxer_t *demuxer)
while (mkv_d->cluster_size > 0)
{
uint64_t block_duration = 0, block_length = 0;
int64_t block_bref = 0;
int64_t block_bref = 0, block_fref = 0;
uint8_t *block = NULL;
while (mkv_d->blockgroup_size > 0)
@ -2925,8 +3053,10 @@ demux_mkv_fill_buffer (demuxer_t *demuxer)
int64_t num = ebml_read_int (s, &l);
if (num == EBML_INT_INVALID)
return 0;
if (num < 0)
if (num <= 0)
block_bref = num;
else
block_fref = num;
break;
}
@ -2944,7 +3074,7 @@ demux_mkv_fill_buffer (demuxer_t *demuxer)
if (block)
{
int res = handle_block (demuxer, block, block_length,
block_duration, block_bref);
block_duration, block_bref, block_fref);
free (block);
if (res < 0)
return 0;
@ -2998,6 +3128,7 @@ demux_mkv_fill_buffer (demuxer_t *demuxer)
void
demux_mkv_seek (demuxer_t *demuxer, float rel_seek_secs, int flags)
{
free_cached_dps (demuxer);
if (!(flags & 2)) /* time in secs */
{
void resync_audio_stream(sh_audio_t *sh_audio);

View File

@ -45,6 +45,8 @@
#define MKV_V_SORENSONV3 "V_SORENSON/V3"
#define MKV_V_CINEPAK "V_CINEPAK"
#define MKV_V_QUICKTIME "V_QUICKTIME"
#define MKV_V_MPEG1 "V_MPEG1"
#define MKV_V_MPEG2 "V_MPEG2"
#define MKV_S_TEXTASCII "S_TEXT/ASCII"
#define MKV_S_TEXTUTF8 "S_TEXT/UTF8"