diff --git a/libavformat/4xm.c b/libavformat/4xm.c index 7db3e602a5..2caa08f4c7 100644 --- a/libavformat/4xm.c +++ b/libavformat/4xm.c @@ -47,6 +47,7 @@ #define MOVI_TAG FOURCC_TAG('M', 'O', 'V', 'I') #define VTRK_TAG FOURCC_TAG('V', 'T', 'R', 'K') #define STRK_TAG FOURCC_TAG('S', 'T', 'R', 'K') +#define std__TAG FOURCC_TAG('s', 't', 'd', '_') #define name_TAG FOURCC_TAG('n', 'a', 'm', 'e') #define vtrk_TAG FOURCC_TAG('v', 't', 'r', 'k') #define strk_TAG FOURCC_TAG('s', 't', 'r', 'k') @@ -82,11 +83,31 @@ typedef struct FourxmDemuxContext { AudioTrack *tracks; int selected_track; - int64_t pts; - int last_chunk_was_audio; - int last_audio_frame_count; + int64_t audio_pts; + int64_t video_pts; + int video_pts_inc; } FourxmDemuxContext; +static float get_le_float(unsigned char *buffer) +{ + float f; + unsigned char *float_buffer = (unsigned char *)&f; + +#ifdef WORDS_BIGENDIAN + float_buffer[0] = buffer[3]; + float_buffer[1] = buffer[2]; + float_buffer[2] = buffer[1]; + float_buffer[3] = buffer[0]; +#else + float_buffer[0] = buffer[0]; + float_buffer[1] = buffer[1]; + float_buffer[2] = buffer[2]; + float_buffer[3] = buffer[3]; +#endif + + return f; +} + static int fourxm_probe(AVProbeData *p) { if (p->buf_size < 12) @@ -111,6 +132,7 @@ static int fourxm_read_header(AVFormatContext *s, int i; int current_track = -1; AVStream *st; + float fps; fourxm->track_count = 0; fourxm->tracks = NULL; @@ -137,7 +159,10 @@ static int fourxm_read_header(AVFormatContext *s, fourcc_tag = LE_32(&header[i]); size = LE_32(&header[i + 4]); - if (fourcc_tag == vtrk_TAG) { + if (fourcc_tag == std__TAG) { + fps = get_le_float(&header[i + 12]); + fourxm->video_pts_inc = (int)(90000.0 / fps); + } else if (fourcc_tag == vtrk_TAG) { /* check that there is enough data */ if (size != vtrk_SIZE) { av_free(header); @@ -180,7 +205,6 @@ static int fourxm_read_header(AVFormatContext *s, fourxm->tracks[current_track].channels = LE_32(&header[i + 36]); fourxm->tracks[current_track].sample_rate = LE_32(&header[i + 40]); fourxm->tracks[current_track].bits = LE_32(&header[i + 44]); - printf("bps:%d\n", fourxm->tracks[current_track].bits); i += 8 + size; /* allocate a new AVStream */ @@ -215,9 +239,8 @@ static int fourxm_read_header(AVFormatContext *s, return AVERROR_INVALIDDATA; /* initialize context members */ - fourxm->pts = 0; - fourxm->last_chunk_was_audio = 0; - fourxm->last_audio_frame_count = 0; + fourxm->video_pts = -fourxm->video_pts_inc; /* first frame will push to 0 */ + fourxm->audio_pts = 0; /* set the pts reference (1 pts = 1/90000) */ s->pts_num = 1; @@ -238,6 +261,7 @@ static int fourxm_read_packet(AVFormatContext *s, int packet_read = 0; unsigned char header[8]; int64_t pts_inc; + int audio_frame_count; while (!packet_read) { @@ -250,6 +274,9 @@ static int fourxm_read_packet(AVFormatContext *s, switch (fourcc_tag) { case LIST_TAG: + /* this is a good time to bump the video pts */ + fourxm->video_pts += fourxm->video_pts_inc; + /* skip the LIST-* tag and move on to the next fourcc */ get_le32(pb); break; @@ -258,21 +285,12 @@ static int fourxm_read_packet(AVFormatContext *s, case pfrm_TAG: case cfrm_TAG:{ - /* bump the pts if the last data sent out was audio */ - if (fourxm->last_chunk_was_audio) { - fourxm->last_chunk_was_audio = 0; - pts_inc = fourxm->last_audio_frame_count; - pts_inc *= 90000; - pts_inc /= fourxm->tracks[fourxm->selected_track].sample_rate; - fourxm->pts += pts_inc; - } - /* allocate 8 more bytes than 'size' to account for fourcc * and size */ if (av_new_packet(pkt, size + 8)) return -EIO; pkt->stream_index = fourxm->video_stream_index; - pkt->pts = fourxm->pts; + pkt->pts = fourxm->video_pts; memcpy(pkt->data, header, 8); ret = get_buffer(&s->pb, &pkt->data[8], size); @@ -293,18 +311,29 @@ static int fourxm_read_packet(AVFormatContext *s, return -EIO; pkt->stream_index = fourxm->tracks[fourxm->selected_track].stream_index; - pkt->pts = fourxm->pts; + pkt->pts = fourxm->audio_pts; ret = get_buffer(&s->pb, pkt->data, size); if (ret < 0) av_free_packet(pkt); else packet_read = 1; - /* maintain pts info for the benefit of the video track */ - fourxm->last_chunk_was_audio = 1; - fourxm->last_audio_frame_count = size / - ((fourxm->tracks[fourxm->selected_track].bits / 8) * - fourxm->tracks[fourxm->selected_track].channels); + /* pts accounting */ + audio_frame_count = size; + if (fourxm->tracks[fourxm->selected_track].adpcm) + audio_frame_count -= + 2 * (fourxm->tracks[fourxm->selected_track].channels); + audio_frame_count /= + fourxm->tracks[fourxm->selected_track].channels; + if (fourxm->tracks[fourxm->selected_track].adpcm) + audio_frame_count *= 2; + else + audio_frame_count /= + (fourxm->tracks[fourxm->selected_track].bits / 8); + pts_inc = audio_frame_count; + pts_inc *= 90000; + pts_inc /= fourxm->tracks[fourxm->selected_track].sample_rate; + fourxm->audio_pts += pts_inc; } else { url_fseek(pb, size, SEEK_CUR);