diff options
-rw-r--r-- | src/demuxers/demux_nsv.c | 503 | ||||
-rw-r--r-- | src/xine-engine/buffer_types.c | 3 |
2 files changed, 317 insertions, 189 deletions
diff --git a/src/demuxers/demux_nsv.c b/src/demuxers/demux_nsv.c index 262584c76..378805a68 100644 --- a/src/demuxers/demux_nsv.c +++ b/src/demuxers/demux_nsv.c @@ -23,7 +23,7 @@ * For more information regarding the NSV file format, visit: * http://www.pcisys.net/~melanson/codecs/ * - * $Id: demux_nsv.c,v 1.18 2004/11/19 00:30:17 tmattern Exp $ + * $Id: demux_nsv.c,v 1.19 2004/11/30 00:41:00 tmattern Exp $ */ #ifdef HAVE_CONFIG_H @@ -50,11 +50,17 @@ #include "buffer.h" #define FOURCC_TAG BE_FOURCC -#define NSVf_TAG FOURCC_TAG('N', 'S', 'V', 'f') -#define NSVs_TAG FOURCC_TAG('N', 'S', 'V', 's') -#define NONE_TAG FOURCC_TAG('N', 'O', 'N', 'E') +#define NSVf_TAG FOURCC_TAG('N', 'S', 'V', 'f') +#define NSVs_TAG FOURCC_TAG('N', 'S', 'V', 's') +#define NONE_TAG FOURCC_TAG('N', 'O', 'N', 'E') -#define BEEF 0xBEEF +#define BEEF 0xEFBE + +#define NSV_MAX_RESYNC (1024 * 1024) +#define NSV_RESYNC_ERROR 0 +#define NSV_RESYNC_BEEF 1 +#define NSV_RESYNC_NSVf 2 +#define NSV_RESYNC_NSVs 3 typedef struct { demux_plugin_t demux_plugin; @@ -73,191 +79,30 @@ typedef struct { unsigned int video_type; int64_t video_pts; unsigned int audio_type; + uint32_t video_fourcc; + uint32_t audio_fourcc; int keyframe_found; + int is_first_chunk; xine_bmiheader bih; + + /* ultravox stuff */ + int is_ultravox; + int ultravox_size; + int ultravox_pos; + int ultravox_first; } demux_nsv_t; typedef struct { demux_class_t demux_class; } demux_nsv_class_t; -/* returns 1 if the NSV file was opened successfully, 0 otherwise */ -static int open_nsv_file(demux_nsv_t *this) { - unsigned char preview[28]; - unsigned int video_fourcc; - unsigned int audio_fourcc; - int is_ultravox = 0; - unsigned int offset = 0; - - if (_x_demux_read_header(this->input, preview, 4) != 4) - return 0; - - /* check for a 'NSV' signature */ - if ((preview[0] != 'N') || - (preview[1] != 'S') || - (preview[2] != 'V')) - { - if ((preview[0] != 'Z') || - (preview[1] != 0) || - (preview[2] != '9') || - (preview[3] != 1)) - return 0; - - is_ultravox = 1; - } - - lprintf("NSV file detected\n"); - - this->data_size = this->input->get_length(this->input); - - if (is_ultravox == 1) { - int i; - unsigned char buffer[512]; - - if (_x_demux_read_header(this->input, buffer, 512) != 512) - return 0; - - for (i = 0; i < 512 - 3; i++) - { - if ((buffer[i] == 'N') && - (buffer[i+1] == 'S') && - (buffer[i+2] == 'V')) { - /* Fill the preview buffer with our nice new NSV tag */ - memcpy (preview, buffer + i, 4); - offset = i; - break; - } - } - } - - /* file is qualified, proceed to load; jump over the first 4 bytes */ - this->input->seek(this->input, 4 + offset, SEEK_SET); - - if (BE_32(&preview[0]) == NSVf_TAG) { - - /* if there is a NSVs tag, load 24 more header bytes; load starting at - * offset 4 in buffer to keep header data in line with document */ - if (this->input->read(this->input, &preview[4], 24) != 24) - return 0; - - lprintf("found NSVf chunk\n"); - this->data_size = BE_32(&preview[8]); - - /* skip the rest of the data */ - this->input->seek(this->input, LE_32(&preview[4]) - 28, SEEK_CUR); - - /* get the first 4 bytes of the next chunk */ - if (this->input->read(this->input, preview, 4) != 4) - return 0; - } - - /* make sure it is a 'NSVs' chunk */ - if (preview[3] != 's') - return 0; - - /* fetch the remaining 12 header bytes of the first chunk to get the - * relevant information */ - if (this->input->read(this->input, &preview[4], 12) != 12) - return 0; - - video_fourcc = ME_32(&preview[4]); - if (BE_32(&preview[4]) == NONE_TAG) - this->video_type = 0; - else - this->video_type = _x_fourcc_to_buf_video(video_fourcc); - - audio_fourcc = ME_32(&preview[8]); - if (BE_32(&preview[8]) == NONE_TAG) - this->audio_type = 0; - else - this->audio_type = _x_formattag_to_buf_audio(audio_fourcc); - - this->bih.biSize = sizeof(this->bih); - this->bih.biWidth = LE_16(&preview[12]); - this->bih.biHeight = LE_16(&preview[14]); - this->bih.biCompression = video_fourcc; - this->video_pts = 0; - - /* may not be true, but set it for the time being */ - this->frame_pts_inc = 3003; - - lprintf("video: %c%c%c%c, buffer type %08X, %dx%d\n", - preview[4], - preview[5], - preview[6], - preview[7], - this->video_type, - this->bih.biWidth, - this->bih.biHeight); - - return 1; -} -static int demux_nsv_send_chunk(demux_plugin_t *this_gen) { - demux_nsv_t *this = (demux_nsv_t *) this_gen; - - unsigned char header[8]; - buf_element_t *buf; - off_t current_file_pos; - int video_size; - int audio_size; - int chunk_id; - - current_file_pos = this->input->get_current_pos(this->input); - - lprintf("dispatching video & audio chunks...\n"); - - /* - * Read 7 bytes and expect the stream to be sitting at 1 of 3 places: - * 1) start of a new 'NSVs' chunk; need to seek over the next 9 bytes, - * read 7 bytes, and move onto case 2 - * 2) at the length info at the start of a NSVs chunk; use the first - * as a FPS byte, read one more byte from the stream and use bytes - * 3-7 as the length info - * 3) at the BEEF marker indicating a new chunk within the NSVs chunk; - * use bytes 2-6 as the length info - */ - - if (this->input->read(this->input, header, 7) != 7) { - this->status = DEMUX_FINISHED; - return this->status; - } - - chunk_id = LE_16(&header[0]); - switch (chunk_id) { - - /* situation #3 from the comment */ - case 0xBEEF: - lprintf("situation #3\n"); - video_size = LE_32(&header[2]); - video_size >>= 4; - video_size &= 0xFFFFF; - audio_size = LE_16(&header[5]); - break; - - /* situation #1 from the comment, characters 'NS' (swapped) from the stream */ - case 0x534E: - lprintf("situation #1\n"); - this->input->seek(this->input, 9, SEEK_CUR); - if (this->input->read(this->input, header, 7) != 7) { - this->status = DEMUX_FINISHED; - return this->status; - } - - /* yes, fall through intentionally to situation #2, per comment */ - - /* situation #2 from the comment */ - default: - lprintf("situation #2\n"); +static void nsv_parse_framerate(demux_nsv_t *this, uint8_t framerate) +{ /* need 1 more byte */ - if (this->input->read(this->input, &header[7], 1) != 1) { - this->status = DEMUX_FINISHED; - return this->status; - } - - this->fps = header[0]; + this->fps = framerate; if (this->fps & 0x80) { switch (this->fps & 0x7F) { case 1: @@ -282,18 +127,236 @@ static int demux_nsv_send_chunk(demux_plugin_t *this_gen) { } } else this->frame_pts_inc = 90000 / this->fps; +} - video_size = LE_32(&header[3]); - video_size >>= 4; - video_size &= 0xFFFFF; - audio_size = LE_16(&header[6]); +static off_t nsv_read(demux_nsv_t *this, uint8_t *buffer, off_t len) { - break; + if (this->is_ultravox != 2) { + + return this->input->read(this->input, buffer, len); + + } else { + + int ultravox_rest; + int buffer_pos = 0; + + /* ultravox stuff */ + while (len) { + ultravox_rest = this->ultravox_size - this->ultravox_pos; + + if (len > ultravox_rest) { + uint8_t ultravox_buf[7]; + + if (ultravox_rest) { + if (this->input->read(this->input, buffer + buffer_pos, ultravox_rest) != ultravox_rest) + return -1; + buffer_pos += ultravox_rest; + len -= ultravox_rest; + } + /* parse ultravox packet header */ + if (this->ultravox_first) { + /* only 6 bytes */ + this->ultravox_first = 0; + ultravox_buf[0] = 0; + if (this->input->read(this->input, ultravox_buf + 1, 6) != 6) + return -1; + } else { + if (this->input->read(this->input, ultravox_buf, 7) != 7) + return -1; + } + /* check signature */ + if ((ultravox_buf[0] != 0x00) || (ultravox_buf[1] != 0x5A)) { + lprintf("lost ultravox sync\n"); + return -1; + } + /* read packet payload len */ + this->ultravox_size = BE_16(&ultravox_buf[5]); + this->ultravox_pos = 0; + lprintf("ultravox_size: %d\n", this->ultravox_size); + } else { + if (this->input->read(this->input, buffer + buffer_pos, len) != len) + return -1; + buffer_pos += len; + this->ultravox_pos += len; + len = 0; + } + } + return buffer_pos; + } +} + +static off_t nsv_seek(demux_nsv_t *this, off_t offset, int origin) { + if (this->is_ultravox != 2) { + + return this->input->seek(this->input, offset, origin); + + } else { + + /* ultravox stuff */ + if (origin == SEEK_CUR) { + uint8_t buffer[1024]; + + while (offset) { + if (offset > sizeof(buffer)) { + if (nsv_read(this, buffer, sizeof(buffer)) != sizeof(buffer)) + return -1; + offset = 0; + } else { + if (nsv_read(this, buffer, offset) != offset) + return -1; + offset -= sizeof(buffer); + } + } + return 0; + + } else { + /* not supported */ + return -1; + } + } +} + +static int nsv_resync(demux_nsv_t *this) { + int i; + uint32_t tag = 0; + + for (i = 0; i < NSV_MAX_RESYNC; i++) { + uint8_t byte; + + if (nsv_read(this, &byte, 1) != 1) + return NSV_RESYNC_ERROR; + +#ifdef LOG + printf("%2X ", byte); +#endif + tag = (tag << 8) | byte; + + if ((tag & 0x0000ffff) == BEEF) { + lprintf("found BEEF after %d bytes\n", i + 1); + return NSV_RESYNC_BEEF; + } else if (tag == NSVs_TAG) { + lprintf("found NSVs after %d bytes\n", i + 1); + return NSV_RESYNC_NSVs; + } else if (tag == NSVf_TAG) { + lprintf("found NSVf after %d bytes\n", i + 1); + return NSV_RESYNC_NSVf; + } + } + lprintf("can't resync\n"); + return NSV_RESYNC_ERROR; +} + + +/* returns 1 if the NSV file was opened successfully, 0 otherwise */ +static int open_nsv_file(demux_nsv_t *this) { + unsigned char preview[28]; + int NSVs_found = 0; + + if (_x_demux_read_header(this->input, preview, 4) != 4) + return 0; + + /* check for a 'NSV' signature */ + if ((preview[0] != 'N') || + (preview[1] != 'S') || + (preview[2] != 'V')) + { + if ((preview[0] != 'Z') || + (preview[1] != 0) || + (preview[2] != '9')) + return 0; + this->is_ultravox = preview[3]; + this->ultravox_first = 1; + } + lprintf("NSV file detected, ultravox=%d\n", this->is_ultravox); + + this->data_size = this->input->get_length(this->input); + + while (!NSVs_found) { + switch (nsv_resync(this)) { + + case NSV_RESYNC_NSVf: + { + uint32_t chunk_size; + + /* if there is a NSVs tag, load 24 more header bytes; load starting at + * offset 4 in buffer to keep header data in line with document */ + if (nsv_read(this, &preview[4], 24) != 24) + return 0; + + lprintf("found NSVf chunk\n"); + /* this->data_size = LE_32(&preview[8]);*/ + /*lprintf("data_size: %lld\n", this->data_size);*/ + + /* skip the rest of the data */ + chunk_size = LE_32(&preview[4]); + nsv_seek(this, chunk_size - 28, SEEK_CUR); + } + break; + + case NSV_RESYNC_NSVs: + + /* fetch the remaining 15 header bytes of the first chunk to get the + * relevant information */ + if (nsv_read(this, &preview[4], 15) != 15) + return 0; + + this->video_fourcc = ME_32(&preview[4]); + if (BE_32(&preview[4]) == NONE_TAG) + this->video_type = 0; + else + this->video_type = _x_fourcc_to_buf_video(this->video_fourcc); + + this->audio_fourcc = ME_32(&preview[8]); + if (BE_32(&preview[8]) == NONE_TAG) + this->audio_type = 0; + else + this->audio_type = _x_formattag_to_buf_audio(this->audio_fourcc); + + this->bih.biSize = sizeof(this->bih); + this->bih.biWidth = LE_16(&preview[12]); + this->bih.biHeight = LE_16(&preview[14]); + this->bih.biCompression = this->video_fourcc; + this->video_pts = 0; + + /* may not be true, but set it for the time being */ + this->frame_pts_inc = 3003; + + lprintf("video: %c%c%c%c, buffer type %08X, %dx%d\n", + preview[4], + preview[5], + preview[6], + preview[7], + this->video_type, + this->bih.biWidth, + this->bih.biHeight); + lprintf("audio: %c%c%c%c, buffer type %08X\n", + preview[8], + preview[9], + preview[10], + preview[11], + this->audio_type); + + nsv_parse_framerate(this, preview[12]); + NSVs_found = 1; + break; + + case NSV_RESYNC_ERROR: + return 0; + + } } - lprintf("sending video chunk with size 0x%X, audio chunk with size 0x%X\n", - video_size, audio_size); + this->is_first_chunk = 1; + return 1; +} + +static int nsv_parse_payload(demux_nsv_t *this, int video_size, int audio_size) { + buf_element_t *buf; + off_t current_file_pos; + + lprintf("video_size=%d, audio_size=%d\n", video_size, audio_size); + current_file_pos = this->input->get_current_pos(this->input); while (video_size) { int buf_num = 0; @@ -306,7 +369,7 @@ static int demux_nsv_send_chunk(demux_plugin_t *this_gen) { buf->size = video_size; video_size -= buf->size; - if (this->input->read(this->input, buf->content, buf->size) != buf->size) { + if (nsv_read(this, buf->content, buf->size) != buf->size) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; @@ -362,26 +425,85 @@ static int demux_nsv_send_chunk(demux_plugin_t *this_gen) { buf->size = audio_size; audio_size -= buf->size; - if (this->input->read(this->input, buf->content, buf->size) != buf->size) { + if (nsv_read(this, buf->content, buf->size) != buf->size) { buf->free_buffer(buf); this->status = DEMUX_FINISHED; return this->status; } buf->type = this->audio_type; + if( this->data_size ) buf->extra_info->input_normpos = (int)((double)current_file_pos * 65535 / this->data_size); buf->extra_info->input_time = this->video_pts / 90; buf->pts = this->video_pts; + buf->decoder_flags |= BUF_FLAG_FRAMERATE; buf->decoder_info[0] = this->frame_pts_inc; if (!audio_size) buf->decoder_flags |= BUF_FLAG_FRAME_END; + this->audio_fifo->put(this->audio_fifo, buf); } this->video_pts += this->frame_pts_inc; + + return this->status; +} + + +static int demux_nsv_send_chunk(demux_plugin_t *this_gen) { + demux_nsv_t *this = (demux_nsv_t *) this_gen; + + uint8_t buffer[15]; + off_t current_file_pos; + int video_size; + int audio_size; + int chunk_type; + + current_file_pos = this->input->get_current_pos(this->input); + + lprintf("dispatching video & audio chunks...\n"); + + if (this->is_first_chunk) { + chunk_type = NSV_RESYNC_BEEF; + this->is_first_chunk = 0; + } else { + chunk_type = nsv_resync(this); + } + + switch (chunk_type) { + case NSV_RESYNC_NSVf: + /* do nothing */ + break; + + case NSV_RESYNC_NSVs: + /* skip header */ + if (nsv_read(this, buffer, 15) != 15) + return 0; + nsv_parse_framerate(this, buffer[12]); + + /* fall thru */ + + case NSV_RESYNC_BEEF: + if (nsv_read(this, buffer, 5) != 5) { + this->status = DEMUX_FINISHED; + return this->status; + } + video_size = LE_32(&buffer[0]); + video_size >>= 4; + video_size &= 0xFFFFF; + audio_size = LE_16(&buffer[3]); + + nsv_parse_payload(this, video_size, audio_size); + break; + + case NSV_RESYNC_ERROR: + this->status = DEMUX_FINISHED; + break; + } + return this->status; } @@ -395,6 +517,10 @@ static void demux_nsv_send_headers(demux_plugin_t *this_gen) { this->status = DEMUX_OK; /* load stream information */ + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_FOURCC, + this->video_fourcc); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, + this->audio_fourcc); _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, (this->video_type) ? 1 : 0); _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, @@ -404,11 +530,12 @@ static void demux_nsv_send_headers(demux_plugin_t *this_gen) { _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->bih.biHeight); + /* send start buffers */ _x_demux_control_start(this->stream); /* send init info to the video decoder */ - if (this->video_fifo && this->video_type) { + if (this->video_type) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE| BUF_FLAG_FRAME_END; diff --git a/src/xine-engine/buffer_types.c b/src/xine-engine/buffer_types.c index 6bf5eac41..fffde62cd 100644 --- a/src/xine-engine/buffer_types.c +++ b/src/xine-engine/buffer_types.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: buffer_types.c,v 1.88 2004/11/24 21:44:57 miguelfreitas Exp $ + * $Id: buffer_types.c,v 1.89 2004/11/30 00:40:59 tmattern Exp $ * * * contents: @@ -856,6 +856,7 @@ static audio_db_t audio_db[] = { meFOURCC('M', 'P', '4', 'A'), meFOURCC('r', 'a', 'a', 'c'), meFOURCC('r', 'a', 'c', 'p'), + meFOURCC('A', 'A', 'C', ' '), 0 }, BUF_AUDIO_AAC, |