mirror of
https://github.com/mpv-player/mpv
synced 2025-01-09 01:36:25 +01: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:
parent
abe3681629
commit
2f83863883
@ -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);
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user