|
|
|
@ -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); |
|
|
|
|