From: Claudio C. <kl...@us...> - 2008-09-05 15:59:46
|
# HG changeset patch # User Claudio Ciccani <kl...@us...> # Date 1220630543 -7200 # Node ID 650d69296d66114855b63e743d32d3cd600bb08d # Parent 4542a8b61c1518bc92ce1a76f5bac9a08f5b576f Updated FLV demuxer. - Added support for new formats introduced by Adobe's Video File Format Specification v9 (including H264 and AAC). - Fixed a problem with seeking when movie length is not specified in the headers. diff -r 650d69296d66114855b63e743d32d3cd600bb08d -r 4542a8b61c1518bc92ce1a76f5bac9a08f5b576f src/demuxers/demux_flv.c --- a/src/demuxers/demux_flv.c Fri Sep 05 18:02:23 2008 +0200 +++ b/src/demuxers/demux_flv.c Thu Aug 14 23:21:27 2008 +0100 @@ -21,10 +21,10 @@ /* * Flash Video (.flv) File Demuxer * by Mike Melanson (mel...@pc...) and - * Claudio Ciccani (kl...@di...) + * Claudio Ciccani (kl...@us...) * * For more information on the FLV file format, visit: - * http://download.macromedia.com/pub/flash/flash_file_format_specification.pdf + * http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v9.pdf */ #ifdef HAVE_CONFIG_H @@ -110,14 +110,20 @@ typedef struct { #define FLV_SOUND_FORMAT_ADPCM 0x01 #define FLV_SOUND_FORMAT_MP3 0x02 #define FLV_SOUND_FORMAT_PCM_LE 0x03 +#define FLV_SOUND_FORMAT_NELLY16 0x04 /* Nellymoser 16KHz */ #define FLV_SOUND_FORMAT_NELLY8 0x05 /* Nellymoser 8KHz */ #define FLV_SOUND_FORMAT_NELLY 0x06 /* Nellymoser */ +#define FLV_SOUND_FORMAT_ALAW 0x07 /* G.711 A-LAW */ +#define FLV_SOUND_FORMAT_MULAW 0x08 /* G.711 MU-LAW */ +#define FLV_SOUND_FORMAT_AAC 0x0a +#define FLV_SOUND_FORMAT_MP38 0x0e /* MP3 8KHz */ #define FLV_VIDEO_FORMAT_FLV1 0x02 /* Sorenson H.263 */ #define FLV_VIDEO_FORMAT_SCREEN 0x03 #define FLV_VIDEO_FORMAT_VP6 0x04 /* On2 VP6 */ #define FLV_VIDEO_FORMAT_VP6A 0x05 /* On2 VP6 with alphachannel */ #define FLV_VIDEO_FORMAT_SCREEN2 0x06 +#define FLV_VIDEO_FORMAT_H264 0x07 #define FLV_DATA_TYPE_NUMBER 0x00 #define FLV_DATA_TYPE_BOOL 0x01 @@ -429,10 +435,23 @@ static int read_flv_packet(demux_flv_t * buf_type = BUF_AUDIO_FLVADPCM; break; case FLV_SOUND_FORMAT_MP3: + case FLV_SOUND_FORMAT_MP38: buf_type = BUF_AUDIO_MPEG; break; case FLV_SOUND_FORMAT_PCM_LE: buf_type = BUF_AUDIO_LPCM_LE; + break; + case FLV_SOUND_FORMAT_ALAW: + buf_type = BUF_AUDIO_ALAW; + break; + case FLV_SOUND_FORMAT_MULAW: + buf_type = BUF_AUDIO_MULAW; + break; + case FLV_SOUND_FORMAT_AAC: + buf_type = BUF_AUDIO_AAC; + /* AAC extra header */ + this->input->read(this->input, buffer, 1 ); + remaining_bytes--; break; default: lprintf(" unsupported audio format (%d)...\n", buffer[0] >> 4); @@ -464,8 +483,17 @@ static int read_flv_packet(demux_flv_t * } remaining_bytes--; - if ((buffer[0] >> 4) == 0x01) - buf_flags = BUF_FLAG_KEYFRAME; + switch ((buffer[0] >> 4)) { + case 0x01: + buf_flags = BUF_FLAG_KEYFRAME; + break; + case 0x05: + /* skip server command */ + this->input->seek(this->input, remaining_bytes, SEEK_CUR); + continue; + default: + break; + } this->videocodec = buffer[0] & 0x0F; /* override */ switch (this->videocodec) { @@ -481,6 +509,12 @@ static int read_flv_packet(demux_flv_t * case FLV_VIDEO_FORMAT_VP6A: buf_type = BUF_VIDEO_VP6F; /* VP6A extra header */ + this->input->read(this->input, buffer, 4); + remaining_bytes -= 4; + break; + case FLV_VIDEO_FORMAT_H264: + buf_type = BUF_VIDEO_H264; + /* AVC extra header */ this->input->read(this->input, buffer, 4); remaining_bytes -= 4; break; @@ -511,6 +545,23 @@ static int read_flv_packet(demux_flv_t * bih->biSize++; buf->size++; } + else if (buf_type == BUF_VIDEO_H264 && buffer[0] == 0) { + /* AVC sequence header */ + if (remaining_bytes > buf->max_size-buf->size) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("sequence header too big (%u bytes)!\n"), remaining_bytes); + this->input->read(this->input, buf->content+buf->size, buf->max_size-buf->size); + this->input->seek(this->input, remaining_bytes-buf->max_size-buf->size, SEEK_CUR); + bih->biSize = buf->max_size; + buf->size = buf->max_size; + } + else { + this->input->read(this->input, buf->content+buf->size, remaining_bytes); + bih->biSize += remaining_bytes; + buf->size += remaining_bytes; + } + remaining_bytes = 0; + } fifo->put(fifo, buf); this->got_video_header = 1; } @@ -537,10 +588,20 @@ static int read_flv_packet(demux_flv_t * buf->type = BUF_AUDIO_FLVADPCM; break; case FLV_SOUND_FORMAT_MP3: + case FLV_SOUND_FORMAT_MP38: buf->type = BUF_AUDIO_MPEG; break; case FLV_SOUND_FORMAT_PCM_LE: buf->type = BUF_AUDIO_LPCM_LE; + break; [... 138 lines omitted ...] pos = this->input->get_current_pos(this->input); @@ -703,7 +792,7 @@ static void seek_flv_file(demux_flv_t *t return; } /* check StreamID and CodecID */ - if ( _X_ME_32(buf) == ME_FOURCC(0, 0, 0, (this->videocodec | 0x10)) ) { + if ( _X_ME_32(buf) == ME_FOURCC(0, 0, 0, (this->videocodec | 0x10)) ) { this->input->seek(this->input, -16, SEEK_CUR); lprintf(" ...resynced after %d bytes\n", i); return; @@ -714,49 +803,50 @@ static void seek_flv_file(demux_flv_t *t lprintf(" ...resync failed!\n"); this->input->seek(this->input, pos, SEEK_SET); - return; } - - while (do_rewind ? (seek_pts < this->cur_pts) : (seek_pts > this->cur_pts)) { - unsigned char tag_type; - int data_size; - int ptag_size; - - if (next_tag) - this->input->seek(this->input, next_tag, SEEK_CUR); - - len = this->input->read(this->input, buffer, 16); - if (len != 16) { - len = (len < 0) ? 0 : len; - break; - } - - ptag_size = _X_BE_32(&buffer[0]); - tag_type = buffer[4]; - data_size = _X_BE_24(&buffer[5]); - pts = _X_BE_24(&buffer[8]) | (buffer[11] << 24); - - if (do_rewind) { - if (!ptag_size) break; /* beginning of movie */ - next_tag = -(ptag_size + 16 + 4); - } - else { - next_tag = data_size - 1; - } + else if (seek_pts) { + while (do_rewind ? (seek_pts < this->cur_pts) : (seek_pts > this->cur_pts)) { + unsigned char tag_type; + int data_size; + int ptag_size; + + if (next_tag) + this->input->seek(this->input, next_tag, SEEK_CUR); + + len = this->input->read(this->input, buffer, 16); + if (len != 16) { + len = (len < 0) ? 0 : len; + break; + } + + ptag_size = _X_BE_32(&buffer[0]); + tag_type = buffer[4]; + data_size = _X_BE_24(&buffer[5]); + pts = _X_BE_24(&buffer[8]) | (buffer[11] << 24); + + if (do_rewind) { + if (!ptag_size) + break; /* beginning of movie */ + next_tag = -(ptag_size + 16 + 4); + } + else { + next_tag = data_size - 1; + } - if (this->flags & FLV_FLAG_HAS_VIDEO) { - /* sync to video key frame */ - if (tag_type != FLV_TAG_TYPE_VIDEO || (buffer[15] >> 4) != 0x01) - continue; - lprintf(" video keyframe found at %d...\n", pts); - } - this->cur_pts = pts; - } - - /* seek back to the beginning of the tag */ - this->input->seek(this->input, -len, SEEK_CUR); - - lprintf( " seeked to %d.\n", pts); + if (this->flags & FLV_FLAG_HAS_VIDEO) { + /* sync to video key frame */ + if (tag_type != FLV_TAG_TYPE_VIDEO || (buffer[15] >> 4) != 0x01) + continue; + lprintf(" video keyframe found at %d...\n", pts); + } + this->cur_pts = pts; + } + + /* seek back to the beginning of the tag */ + this->input->seek(this->input, -len, SEEK_CUR); + + lprintf( " seeked to %d.\n", pts); + } } @@ -806,8 +896,12 @@ static int demux_flv_seek (demux_plugin_ this->status = DEMUX_OK; if (INPUT_IS_SEEKABLE(this->input)) { - if (start_pos && !start_time) - start_time = (int64_t) this->length * start_pos / 65535; + if (start_pos && !start_time) { + if (this->length) + start_time = (int64_t) this->length * start_pos / 65535; + else if (this->index) + start_time = this->index[(int)(start_pos * (this->num_indices-1) / 65535)].pts; + } if (!this->length || start_time < this->length) { seek_flv_file(this, start_pos, start_time); @@ -825,7 +919,8 @@ static void demux_flv_dispose (demux_plu static void demux_flv_dispose (demux_plugin_t *this_gen) { demux_flv_t *this = (demux_flv_t *) this_gen; - free(this->index); + if (this->index) + free(this->index); free(this); } |