aboutsummaryrefslogtreecommitdiffhomepage
path: root/libmpdemux
diff options
context:
space:
mode:
authorGravatar arpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2>2001-10-20 18:49:08 +0000
committerGravatar arpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2>2001-10-20 18:49:08 +0000
commit881e5d0783d66de0d3efe4b633aa413a277c5b18 (patch)
tree998f3cdd340f82a73f54b1cdc4e22c19dabff4ad /libmpdemux
parentdaab5f2480c62bbe684e09e0ae979958b447124b (diff)
libdemuxer...
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@2311 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpdemux')
-rw-r--r--libmpdemux/asf.h200
-rw-r--r--libmpdemux/asf_streaming.c353
-rw-r--r--libmpdemux/asfheader.c279
-rw-r--r--libmpdemux/aviheader.c241
-rw-r--r--libmpdemux/aviheader.h106
-rw-r--r--libmpdemux/aviprint.c102
-rw-r--r--libmpdemux/aviwrite.c172
-rw-r--r--libmpdemux/bswap.h2
-rw-r--r--libmpdemux/codec-cfg.h0
-rw-r--r--libmpdemux/config.h2
-rw-r--r--libmpdemux/demux_asf.c367
-rw-r--r--libmpdemux/demux_avi.c673
-rw-r--r--libmpdemux/demux_mov.c613
-rw-r--r--libmpdemux/demux_mpg.c403
-rw-r--r--libmpdemux/demuxer.c580
-rw-r--r--libmpdemux/demuxer.h155
-rw-r--r--libmpdemux/dvdauth.c229
-rw-r--r--libmpdemux/dvdauth.h16
-rw-r--r--libmpdemux/help_mp.h1
-rw-r--r--libmpdemux/http.c296
-rw-r--r--libmpdemux/http.h44
-rw-r--r--libmpdemux/mp_msg.h2
-rw-r--r--libmpdemux/network.c592
-rw-r--r--libmpdemux/network.h49
-rw-r--r--libmpdemux/open.c437
-rw-r--r--libmpdemux/parse_es.c117
-rw-r--r--libmpdemux/parse_es.h18
-rw-r--r--libmpdemux/stheader.h94
-rw-r--r--libmpdemux/stream.c188
-rw-r--r--libmpdemux/stream.h141
-rw-r--r--libmpdemux/test.c66
-rw-r--r--libmpdemux/url.c117
-rw-r--r--libmpdemux/url.h23
-rw-r--r--libmpdemux/vcd_read.h280
-rw-r--r--libmpdemux/vcd_read_fbsd.h143
35 files changed, 7101 insertions, 0 deletions
diff --git a/libmpdemux/asf.h b/libmpdemux/asf.h
new file mode 100644
index 0000000000..8d35563cda
--- /dev/null
+++ b/libmpdemux/asf.h
@@ -0,0 +1,200 @@
+#ifndef __ASF_H
+#define __ASF_H
+
+#include "config.h" /* for WORDS_BIGENDIAN */
+#include <inttypes.h>
+#include "bswap.h"
+#ifdef STREAMING
+#include "network.h"
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a<b)?a:b)
+#endif
+
+///////////////////////
+// MS GUID definition
+///////////////////////
+#ifndef GUID_DEFINED
+#define GUID_DEFINED
+// Size of GUID is 16 bytes!
+typedef struct __attribute__((packed)) {
+ uint32_t Data1; // 4 bytes
+ uint16_t Data2; // 2 bytes
+ uint16_t Data3; // 2 bytes
+ uint8_t Data4[8]; // 8 bytes
+} GUID_t;
+#endif
+
+///////////////////////
+// ASF Object Header
+///////////////////////
+typedef struct __attribute__((packed)) {
+ uint8_t guid[16];
+ uint64_t size;
+} ASF_obj_header_t;
+
+////////////////
+// ASF Header
+////////////////
+typedef struct __attribute__((packed)) {
+ ASF_obj_header_t objh;
+ uint32_t cno; // number of subchunks
+ uint8_t v1; // unknown (0x01)
+ uint8_t v2; // unknown (0x02)
+} ASF_header_t;
+
+/////////////////////
+// ASF File Header
+/////////////////////
+typedef struct __attribute__((packed)) {
+ uint8_t client[16]; // Client GUID
+ uint64_t file_size;
+ uint64_t creat_time; //File creation time FILETIME 8
+ uint64_t packets; //Number of packets UINT64 8
+ uint64_t end_timestamp; //Timestamp of the end position UINT64 8
+ uint64_t duration; //Duration of the playback UINT64 8
+ uint32_t start_timestamp; //Timestamp of the start position UINT32 4
+ uint32_t unk1; //Unknown, maybe reserved ( usually contains 0 ) UINT32 4
+ uint32_t flags; //Unknown, maybe flags ( usually contains 2 ) UINT32 4
+ uint32_t packetsize; //Size of packet, in bytes UINT32 4
+ uint32_t packetsize2; //Size of packet ( confirm ) UINT32 4
+ uint32_t frame_size; //Size of uncompressed video frame UINT32 4
+} ASF_file_header_t;
+
+///////////////////////
+// ASF Stream Header
+///////////////////////
+typedef struct __attribute__((packed)) {
+ uint8_t type[16]; // Stream type (audio/video) GUID 16
+ uint8_t concealment[16]; // Audio error concealment type GUID 16
+ uint64_t unk1; // Unknown, maybe reserved ( usually contains 0 ) UINT64 8
+ uint32_t type_size; //Total size of type-specific data UINT32 4
+ uint32_t stream_size; //Size of stream-specific data UINT32 4
+ uint16_t stream_no; //Stream number UINT16 2
+ uint32_t unk2; //Unknown UINT32 4
+} ASF_stream_header_t;
+
+///////////////////////////
+// ASF Content Description
+///////////////////////////
+typedef struct __attribute__((packed)) {
+ uint16_t title_size;
+ uint16_t author_size;
+ uint16_t copyright_size;
+ uint16_t comment_size;
+ uint16_t rating_size;
+} ASF_content_description_t;
+
+////////////////////////
+// ASF Segment Header
+////////////////////////
+typedef struct __attribute__((packed)) {
+ uint8_t streamno;
+ uint8_t seq;
+ uint32_t x;
+ uint8_t flag;
+} ASF_segmhdr_t;
+
+//////////////////////
+// ASF Stream Chunck
+//////////////////////
+typedef struct __attribute__((packed)) {
+ uint16_t type;
+ uint16_t size;
+ uint32_t sequence_number;
+ uint16_t unknown;
+ uint16_t size_confirm;
+} ASF_stream_chunck_t;
+
+
+// Definition of the differents type of ASF streaming
+typedef enum {
+ ASF_Unknown_e,
+ ASF_Live_e,
+ ASF_Prerecorded_e,
+ ASF_Redirector_e
+} ASF_StreamType_e;
+
+
+/*
+ * Some macros to swap little endian structures read from an ASF file
+ * into machine endian format
+ */
+#ifdef WORDS_BIGENDIAN
+#define le2me_ASF_obj_header_t(h) { \
+ (h)->size = le2me_64((h)->size); \
+}
+#define le2me_ASF_header_t(h) { \
+ le2me_ASF_obj_header_t(&(h)->objh); \
+ (h)->cno = le2me_32((h)->cno); \
+}
+#define le2me_ASF_stream_header_t(h) { \
+ (h)->unk1 = le2me_64((h)->unk1); \
+ (h)->type_size = le2me_32((h)->type_size); \
+ (h)->stream_size = le2me_32((h)->stream_size); \
+ (h)->stream_no = le2me_16((h)->stream_no); \
+ (h)->unk2 = le2me_32((h)->unk2); \
+}
+#define le2me_ASF_file_header_t(h) { \
+ (h)->file_size = le2me_64((h)->file_size); \
+ (h)->creat_time = le2me_64((h)->creat_time); \
+ (h)->packets = le2me_64((h)->packets); \
+ (h)->end_timestamp = le2me_64((h)->end_timestamp); \
+ (h)->duration = le2me_64((h)->duration); \
+ (h)->start_timestamp = le2me_32((h)->start_timestamp); \
+ (h)->unk1 = le2me_32((h)->unk1); \
+ (h)->flags = le2me_32((h)->flags); \
+ (h)->packetsize = le2me_32((h)->packetsize); \
+ (h)->packetsize2 = le2me_32((h)->packetsize2); \
+ (h)->frame_size = le2me_32((h)->frame_size); \
+}
+#define le2me_ASF_content_description_t(h) { \
+ (h)->title_size = le2me_16((h)->title_size); \
+ (h)->author_size = le2me_16((h)->author_size); \
+ (h)->copyright_size = le2me_16((h)->copyright_size); \
+ (h)->comment_size = le2me_16((h)->comment_size); \
+ (h)->rating_size = le2me_16((h)->rating_size); \
+}
+#define le2me_BITMAPINFOHEADER(h) { \
+ (h)->biSize = le2me_32((h)->biSize); \
+ (h)->biWidth = le2me_32((h)->biWidth); \
+ (h)->biHeight = le2me_32((h)->biHeight); \
+ (h)->biPlanes = le2me_16((h)->biPlanes); \
+ (h)->biBitCount = le2me_16((h)->biBitCount); \
+ (h)->biCompression = le2me_32((h)->biCompression); \
+ (h)->biSizeImage = le2me_32((h)->biSizeImage); \
+ (h)->biXPelsPerMeter = le2me_32((h)->biXPelsPerMeter); \
+ (h)->biYPelsPerMeter = le2me_32((h)->biYPelsPerMeter); \
+ (h)->biClrUsed = le2me_32((h)->biClrUsed); \
+ (h)->biClrImportant = le2me_32((h)->biClrImportant); \
+}
+#define le2me_WAVEFORMATEX(h) { \
+ (h)->wFormatTag = le2me_16((h)->wFormatTag); \
+ (h)->nChannels = le2me_16((h)->nChannels); \
+ (h)->nSamplesPerSec = le2me_32((h)->nSamplesPerSec); \
+ (h)->nAvgBytesPerSec = le2me_32((h)->nAvgBytesPerSec); \
+ (h)->nBlockAlign = le2me_16((h)->nBlockAlign); \
+ (h)->wBitsPerSample = le2me_16((h)->wBitsPerSample); \
+ (h)->cbSize = le2me_16((h)->cbSize); \
+}
+#else
+#define le2me_ASF_obj_header_t(h) /**/
+#define le2me_ASF_header_t(h) /**/
+#define le2me_ASF_stream_header_t(h) /**/
+#define le2me_ASF_file_header_t(h) /**/
+#define le2me_ASF_content_description_t(h) /**/
+#define le2me_BITMAPINFOHEADER(h) /**/
+#define le2me_WAVEFORMATEX(h) /**/
+#endif
+
+
+#ifdef STREAMING
+int asf_http_streaming_type(char *content_type, char *features);
+int asf_http_streaming_start( streaming_ctrl_t *streaming_ctrl );
+int asf_http_streaming_read( streaming_ctrl_t *streaming_ctrl );
+
+int asf_streaming(char *data, int length, int *drop_packet );
+#endif
+
+#endif
diff --git a/libmpdemux/asf_streaming.c b/libmpdemux/asf_streaming.c
new file mode 100644
index 0000000000..5205a143b6
--- /dev/null
+++ b/libmpdemux/asf_streaming.c
@@ -0,0 +1,353 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "url.h"
+#include "http.h"
+#include "asf.h"
+#include "network.h"
+
+#include "stream.h"
+//#include "demuxer.h"
+
+//extern demuxer_t *demuxer;
+
+static ASF_StreamType_e streaming_type = ASF_Unknown_e;
+
+int
+asf_http_streaming_read( streaming_ctrl_t *streaming_ctrl ) {
+ char *buffer;
+ int drop_packet;
+ int ret;
+printf("asf_streaming_read\n");
+ ret = asf_streaming( streaming_ctrl->buffer->buffer, streaming_ctrl->buffer->length, &drop_packet );
+printf("ret: %d\n", ret);
+ if( ret<0 ) return -1;
+ if( ret>streaming_ctrl->buffer->length ) return 0;
+ buffer = (char*)malloc(ret);
+ if( buffer==NULL ) {
+ printf("Memory allocation failed\n");
+ return -1;
+ }
+printf("buffer length: %d\n", streaming_ctrl->buffer->length );
+ net_fifo_pop( streaming_ctrl->buffer, buffer, ret );
+printf(" pop: 0x%02X\n", *((unsigned int*)buffer) );
+printf("buffer length: %d\n", streaming_ctrl->buffer->length );
+printf("0x%02X\n", *((unsigned int*)(buffer+sizeof(ASF_stream_chunck_t))) );
+ if( !drop_packet ) {
+ write( streaming_ctrl->fd_pipe_in, buffer+sizeof(ASF_stream_chunck_t), ret-sizeof(ASF_stream_chunck_t) );
+ }
+ free( buffer );
+ return ret;
+}
+
+int
+asf_streaming(char *data, int length, int *drop_packet ) {
+ ASF_stream_chunck_t *stream_chunck=(ASF_stream_chunck_t*)data;
+ printf("ASF stream chunck size=%d\n", stream_chunck->size);
+printf("length: %d\n", length );
+printf("0x%02X\n", stream_chunck->type );
+
+ if( drop_packet!=NULL ) *drop_packet = 0;
+ if( data==NULL || length<=0 ) return -1;
+
+ if( stream_chunck->size<8 ) {
+ printf("Ahhhh, stream_chunck size is too small: %d\n", stream_chunck->size);
+ return -1;
+ }
+ if( stream_chunck->size!=stream_chunck->size_confirm ) {
+ printf("size_confirm mismatch!: %d %d\n", stream_chunck->size, stream_chunck->size_confirm);
+ return -1;
+ }
+
+ printf(" type: 0x%02X\n", stream_chunck->type );
+ printf(" size: %d (0x%02X)\n", stream_chunck->size, stream_chunck->size );
+ printf(" sequence_number: 0x%04X\n", stream_chunck->sequence_number );
+ printf(" unknown: 0x%02X\n", stream_chunck->unknown );
+ printf(" size_confirm: 0x%02X\n", stream_chunck->size_confirm );
+
+
+ switch(stream_chunck->type) {
+ case 0x4324: // Clear ASF configuration
+ printf("=====> Clearing ASF stream configuration!\n");
+ if( drop_packet!=NULL ) *drop_packet = 1;
+ return stream_chunck->size;
+ break;
+ case 0x4424: // Data follows
+ printf("=====> Data follows\n");
+ break;
+ case 0x4524: // Transfer complete
+ printf("=====> Transfer complete\n");
+ if( drop_packet!=NULL ) *drop_packet = 1;
+ return stream_chunck->size;
+ break;
+ case 0x4824: // ASF header chunk follows
+ printf("=====> ASF header chunk follows\n");
+ break;
+ default:
+ printf("=====> Unknown stream type 0x%x\n", stream_chunck->type );
+ }
+ return stream_chunck->size+4;
+}
+
+int
+asf_http_streaming_type(char *content_type, char *features) {
+ if( content_type==NULL ) return ASF_Unknown_e;
+ if( !strcasecmp(content_type, "application/octet-stream") ) {
+ if( features==NULL ) {
+ printf("=====> ASF Prerecorded\n");
+ return ASF_Prerecorded_e;
+ } else if( strstr(features, "broadcast")) {
+ printf("=====> ASF Live stream\n");
+ return ASF_Live_e;
+ } else {
+ printf("=====> ASF Prerecorded\n");
+ return ASF_Prerecorded_e;
+ }
+ } else {
+ if( (!strcasecmp(content_type, "audio/x-ms-wax")) ||
+ (!strcasecmp(content_type, "audio/x-ms-wma")) ||
+ (!strcasecmp(content_type, "video/x-ms-asf")) ||
+ (!strcasecmp(content_type, "video/x-ms-afs")) ||
+ (!strcasecmp(content_type, "video/x-ms-wvx")) ||
+ (!strcasecmp(content_type, "video/x-ms-wmv")) ||
+ (!strcasecmp(content_type, "video/x-ms-wma")) ) {
+ printf("=====> ASF Redirector\n");
+ return ASF_Redirector_e;
+ } else {
+ printf("=====> ASF unknown content-type: %s\n", content_type );
+ return ASF_Unknown_e;
+ }
+ }
+ return ASF_Unknown_e;
+}
+
+HTTP_header_t *
+asf_http_request(URL_t *url) {
+ HTTP_header_t *http_hdr;
+ char str[250];
+ char *ptr;
+ char *request;
+ int i;
+
+ int offset_hi=0, offset_lo=0, req_nb=1, length=0;
+ int asf_nb_stream;
+
+ // Common header for all requests.
+ http_hdr = http_new_header();
+ http_set_uri( http_hdr, url->file );
+ http_set_field( http_hdr, "Accept: */*" );
+ http_set_field( http_hdr, "User-Agent: NSPlayer/4.1.0.3856" );
+ sprintf( str, "Host: %s:%d", url->hostname, url->port );
+ http_set_field( http_hdr, str );
+ http_set_field( http_hdr, "Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}" );
+ sprintf(str,
+ "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=%u",
+ offset_hi, offset_lo, req_nb, length );
+ http_set_field( http_hdr, str );
+
+ switch( streaming_type ) {
+ case ASF_Live_e:
+ case ASF_Prerecorded_e:
+ http_set_field( http_hdr, "Pragma: xPlayStrm=1" );
+ ptr = str;
+ ptr += sprintf( ptr, "Pragma: stream-switch-entry=");
+
+// FIXME: why do you need demuxer here? if you really need it, pass it as
+// parameter. -- A'rpi
+
+#if 0
+ for( i=0, asf_nb_stream=0 ; i<256 ; i++ ) {
+ // FIXME START
+ if( demuxer==NULL ) {
+ ptr += sprintf( ptr, " ffff:1:0" );
+ asf_nb_stream = 1;
+ break;
+ }
+ // FIXME END
+ if( demuxer->a_streams[i] ) {
+ ptr += sprintf( ptr, " ffff:%d:0", i );
+ asf_nb_stream++;
+ }
+ if( demuxer->v_streams[i] ) {
+ ptr += sprintf( ptr, " ffff:%d:0", i );
+ asf_nb_stream++;
+ }
+ }
+#endif
+ http_set_field( http_hdr, str );
+ sprintf( str, "Pragma: stream-switch-count=%d", asf_nb_stream );
+ http_set_field( http_hdr, str );
+ break;
+ case ASF_Redirector_e:
+ break;
+ case ASF_Unknown_e:
+ // First request goes here.
+ break;
+ default:
+ printf("Unknown asf stream type\n");
+ }
+
+ http_set_field( http_hdr, "Connection: Close" );
+ http_build_request( http_hdr );
+
+ return http_hdr;
+}
+
+int
+asf_http_parse_response( HTTP_header_t *http_hdr ) {
+ char *content_type, *pragma;
+ char features[64] = "\0";
+ int len;
+ if( http_response_parse(http_hdr)<0 ) {
+ printf("Failed to parse HTTP response\n");
+ return -1;
+ }
+ if( http_hdr->status_code!=200 ) {
+ printf("Server return %d:%s\n", http_hdr->status_code, http_hdr->reason_phrase);
+ return -1;
+ }
+
+ content_type = http_get_field( http_hdr, "Content-Type");
+
+ pragma = http_get_field( http_hdr, "Pragma");
+ while( pragma!=NULL ) {
+ char *comma_ptr=NULL;
+ char *end;
+ // The pragma line can get severals attributes
+ // separeted with a comma ','.
+ do {
+ if( !strncasecmp( pragma, "features=", 9) ) {
+ pragma += 9;
+ end = strstr( pragma, "," );
+ if( end==NULL ) {
+ len = strlen(pragma);
+ }
+ len = MIN(end-pragma,sizeof(features));
+ strncpy( features, pragma, len );
+ features[len]='\0';
+ break;
+ }
+ comma_ptr = strstr( pragma, "," );
+ if( comma_ptr!=NULL ) {
+ pragma = comma_ptr+1;
+ if( pragma[0]==' ' ) pragma++;
+ }
+ } while( comma_ptr!=NULL );
+ pragma = http_get_next_field( http_hdr );
+ }
+
+ streaming_type = asf_http_streaming_type( content_type, features );
+
+ if( http_hdr->body_size>0 ) {
+ asf_streaming( http_hdr->body, http_hdr->body_size, NULL);
+ }
+
+ return 0;
+}
+
+URL_t *
+asf_http_ASX_redirect( HTTP_header_t *http_hdr ) {
+ URL_t *url_redirect=NULL;
+ printf("=========>> ASX parser not yet implemented <<==========\n");
+
+ printf("ASX=[%s]\n", http_hdr->body );
+
+ return url_redirect;
+}
+
+int
+asf_http_streaming_start( streaming_ctrl_t *streaming_ctrl ) {
+ HTTP_header_t *http_hdr=NULL;
+ URL_t *url_next=NULL;
+ URL_t *url = *(streaming_ctrl->url);
+ char buffer[BUFFER_SIZE];
+ int i;
+ int fd = streaming_ctrl->fd_net;
+ int done=1;
+
+streaming_type = ASF_Live_e;
+ do {
+ if( fd>0 ) close( fd );
+
+ fd = connect2Server( url->hostname, url->port );
+ if( fd<0 ) return -1;
+
+ http_hdr = asf_http_request( url );
+printf("[%s]\n", http_hdr->buffer );
+ write( fd, http_hdr->buffer, http_hdr->buffer_size );
+// http_free( http_hdr );
+
+ http_hdr = http_new_header();
+ do {
+ i = readFromServer( fd, buffer, BUFFER_SIZE );
+printf("read: %d\n", i );
+ if( i<0 ) {
+ perror("read");
+ http_free( http_hdr );
+ return -1;
+ }
+ http_response_append( http_hdr, buffer, i );
+ } while( !http_is_header_entired( http_hdr ) );
+//http_hdr->buffer[http_hdr->buffer_len]='\0';
+//printf("[%s]\n", http_hdr->buffer );
+ if( asf_http_parse_response(http_hdr)<0 ) {
+ printf("Failed to parse header\n");
+ http_free( http_hdr );
+ return -1;
+ }
+ switch( streaming_type ) {
+ case ASF_Live_e:
+ case ASF_Prerecorded_e:
+ if( http_hdr->body_size>0 ) {
+printf("--- 0x%02X\n", streaming_ctrl->buffer );
+ net_fifo_push( streaming_ctrl->buffer, http_hdr->body, http_hdr->body_size );
+ } else {
+ ASF_stream_chunck_t *ptr;
+ int ret;
+ i = readFromServer( fd, buffer, sizeof(ASF_stream_chunck_t) );
+printf("read: %d\n", i );
+ ret = asf_streaming( buffer, i, NULL );
+ net_fifo_push( streaming_ctrl->buffer, buffer, i );
+ ptr = (ASF_stream_chunck_t*)buffer;
+ if( ret==ptr->size ) {
+ }
+ }
+// done = 0;
+ break;
+ case ASF_Redirector_e:
+ url_next = asf_http_ASX_redirect( http_hdr );
+ if( url_next==NULL ) {
+ printf("Failed to parse ASX file\n");
+ close(fd);
+ http_free( http_hdr );
+ return -1;
+ }
+ if( url_next->port==0 ) url_next->port=80;
+ url_free( url );
+ url = url_next;
+ *(streaming_ctrl->url) = url_next;
+ url_next = NULL;
+ break;
+ case ASF_Unknown_e:
+ default:
+ printf("Unknown ASF streaming type\n");
+ close(fd);
+ http_free( http_hdr );
+ return -1;
+ }
+
+ // Check if we got a redirect.
+ } while(!done);
+
+ streaming_ctrl->fd_net = fd;
+ streaming_ctrl->streaming_read = asf_http_streaming_read;
+ streaming_ctrl->prebuffer_size = 10000;
+ streaming_ctrl->buffering = 1;
+ streaming_ctrl->status = streaming_playing_e;
+
+ http_free( http_hdr );
+ return fd;
+}
+
diff --git a/libmpdemux/asfheader.c b/libmpdemux/asfheader.c
new file mode 100644
index 0000000000..d8349c6499
--- /dev/null
+++ b/libmpdemux/asfheader.c
@@ -0,0 +1,279 @@
+// .asf fileformat docs from http://divx.euro.ru
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern int verbose; // defined in mplayer.c
+
+#include "config.h"
+#include "mp_msg.h"
+
+#include "stream.h"
+#include "demuxer.h"
+
+#include "wine/mmreg.h"
+#include "wine/avifmt.h"
+#include "wine/vfw.h"
+
+#include "codec-cfg.h"
+#include "stheader.h"
+//#include "aviheader.h"
+#include "asf.h"
+
+#ifdef ARCH_X86
+#define ASF_LOAD_GUID_PREFIX(guid) (*(uint32_t *)(guid))
+#else
+#define ASF_LOAD_GUID_PREFIX(guid) \
+ ((guid)[3] << 24 | (guid)[2] << 16 | (guid)[1] << 8 | (guid)[0])
+#endif
+
+#define ASF_GUID_PREFIX_audio_stream 0xF8699E40
+#define ASF_GUID_PREFIX_video_stream 0xBC19EFC0
+#define ASF_GUID_PREFIX_audio_conceal_none 0x49f1a440
+#define ASF_GUID_PREFIX_audio_conceal_interleave 0xbfc3cd50
+#define ASF_GUID_PREFIX_header 0x75B22630
+#define ASF_GUID_PREFIX_data_chunk 0x75b22636
+#define ASF_GUID_PREFIX_index_chunk 0x33000890
+#define ASF_GUID_PREFIX_stream_header 0xB7DC0791
+#define ASF_GUID_PREFIX_header_2_0 0xD6E229D1
+#define ASF_GUID_PREFIX_file_header 0x8CABDCA1
+#define ASF_GUID_PREFIX_content_desc 0x75b22633
+
+
+static ASF_header_t asfh;
+static ASF_obj_header_t objh;
+static ASF_file_header_t fileh;
+static ASF_stream_header_t streamh;
+static ASF_content_description_t contenth;
+
+unsigned char* asf_packet=NULL;
+int asf_scrambling_h=1;
+int asf_scrambling_w=1;
+int asf_scrambling_b=1;
+int asf_packetsize=0;
+
+//int i;
+
+// the variable string is modify in this function
+void pack_asf_string(char* string, int length) {
+ int i,j;
+ if( string==NULL ) return;
+ for( i=0, j=0; i<length && string[i]!='\0'; i+=2, j++) {
+ string[j]=string[i];
+ }
+ string[j]='\0';
+}
+
+// the variable string is modify in this function
+void print_asf_string(const char* name, char* string, int length) {
+ pack_asf_string(string, length);
+ mp_msg(MSGT_HEADER,MSGL_V,"%s%s\n", name, string);
+}
+
+static char* asf_chunk_type(unsigned char* guid) {
+ static char tmp[60];
+ char *p;
+ int i;
+
+ switch(ASF_LOAD_GUID_PREFIX(guid)){
+ case ASF_GUID_PREFIX_audio_stream:
+ return "guid_audio_stream";
+ case ASF_GUID_PREFIX_video_stream:
+ return "guid_video_stream";
+ case ASF_GUID_PREFIX_audio_conceal_none:
+ return "guid_audio_conceal_none";
+ case ASF_GUID_PREFIX_audio_conceal_interleave:
+ return "guid_audio_conceal_interleave";
+ case ASF_GUID_PREFIX_header:
+ return "guid_header";
+ case ASF_GUID_PREFIX_data_chunk:
+ return "guid_data_chunk";
+ case ASF_GUID_PREFIX_index_chunk:
+ return "guid_index_chunk";
+ case ASF_GUID_PREFIX_stream_header:
+ return "guid_stream_header";
+ case ASF_GUID_PREFIX_header_2_0:
+ return "guid_header_2_0";
+ case ASF_GUID_PREFIX_file_header:
+ return "guid_file_header";
+ case ASF_GUID_PREFIX_content_desc:
+ return "guid_content_desc";
+ default:
+ strcpy(tmp, "unknown guid ");
+ p = tmp + strlen(tmp);
+ for (i = 0; i < 16; i++) {
+ if ((1 << i) & ((1<<4) | (1<<6) | (1<<8))) *p++ = '-';
+ sprintf(p, "%02x", guid[i]);
+ p += 2;
+ }
+ return tmp;
+ }
+}
+
+int asf_check_header(demuxer_t *demuxer){
+ unsigned char asfhdrguid[16]={0x30,0x26,0xB2,0x75,0x8E,0x66,0xCF,0x11,0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C};
+ stream_read(demuxer->stream,(char*) &asfh,sizeof(asfh)); // header obj
+ le2me_ASF_header_t(&asfh); // swap to machine endian
+// for(i=0;i<16;i++) printf(" %02X",temp[i]);printf("\n");
+// for(i=0;i<16;i++) printf(" %02X",asfhdrguid[i]);printf("\n");
+ if(memcmp(asfhdrguid,asfh.objh.guid,16)){
+ mp_msg(MSGT_HEADER,MSGL_V,"ASF_check: not ASF guid!\n");
+ return 0; // not ASF guid
+ }
+ if(asfh.cno>256){
+ mp_msg(MSGT_HEADER,MSGL_V,"ASF_check: invalid subchunks_no %d\n",(int) asfh.cno);
+ return 0; // invalid header???
+ }
+ return 1;
+}
+
+extern void print_wave_header(WAVEFORMATEX *h);
+extern void print_video_header(BITMAPINFOHEADER *h);
+
+int read_asf_header(demuxer_t *demuxer){
+ static unsigned char buffer[1024];
+
+#if 1
+ //printf("ASF file! (subchunks: %d)\n",asfh.cno);
+while(!stream_eof(demuxer->stream)){
+ int pos,endpos;
+ pos=stream_tell(demuxer->stream);
+ stream_read(demuxer->stream,(char*) &objh,sizeof(objh));
+ le2me_ASF_obj_header_t(&objh);
+ if(stream_eof(demuxer->stream)) break; // EOF
+ endpos=pos+objh.size;
+// for(i=0;i<16;i++) printf("%02X ",objh.guid[i]);
+ //printf("0x%08X [%s] %d\n",pos, asf_chunk_type(objh.guid),(int) objh.size);
+ switch(ASF_LOAD_GUID_PREFIX(objh.guid)){
+ case ASF_GUID_PREFIX_stream_header:
+ stream_read(demuxer->stream,(char*) &streamh,sizeof(streamh));
+ le2me_ASF_stream_header_t(&streamh);
+ if(verbose){
+ mp_msg(MSGT_HEADER,MSGL_V,"stream type: %s\n",asf_chunk_type(streamh.type));
+ mp_msg(MSGT_HEADER,MSGL_V,"stream concealment: %s\n",asf_chunk_type(streamh.concealment));
+ mp_msg(MSGT_HEADER,MSGL_V,"type: %d bytes, stream: %d bytes ID: %d\n",(int)streamh.type_size,(int)streamh.stream_size,(int)streamh.stream_no);
+ mp_msg(MSGT_HEADER,MSGL_V,"unk1: %lX unk2: %X\n",(unsigned long)streamh.unk1,(unsigned int)streamh.unk2);
+ mp_msg(MSGT_HEADER,MSGL_V,"FILEPOS=0x%X\n",stream_tell(demuxer->stream));
+ }
+ if(streamh.type_size>1024 || streamh.stream_size>1024){
+ mp_msg(MSGT_HEADER,MSGL_FATAL,"FATAL: header size bigger than 1024 bytes!\n"
+ "Please contact mplayer authors, and upload/send this file.\n");
+ return 0;
+ }
+ // type-specific data:
+ stream_read(demuxer->stream,(char*) buffer,streamh.type_size);
+ switch(ASF_LOAD_GUID_PREFIX(streamh.type)){
+ case ASF_GUID_PREFIX_audio_stream: {
+ sh_audio_t* sh_audio=new_sh_audio(demuxer,streamh.stream_no & 0x7F);
+ sh_audio->wf=calloc((streamh.type_size<sizeof(WAVEFORMATEX))?sizeof(WAVEFORMATEX):streamh.type_size,1);
+ memcpy(sh_audio->wf,buffer,streamh.type_size);
+ le2me_WAVEFORMATEX(sh_audio->wf);
+ if(verbose>=1) print_wave_header(sh_audio->wf);
+ if(ASF_LOAD_GUID_PREFIX(streamh.concealment)==ASF_GUID_PREFIX_audio_conceal_interleave){
+ stream_read(demuxer->stream,(char*) buffer,streamh.stream_size);
+ asf_scrambling_h=buffer[0];
+ asf_scrambling_w=(buffer[2]<<8)|buffer[1];
+ asf_scrambling_b=(buffer[4]<<8)|buffer[3];
+ asf_scrambling_w/=asf_scrambling_b;
+ } else {
+ asf_scrambling_b=asf_scrambling_h=asf_scrambling_w=1;
+ }
+ mp_msg(MSGT_HEADER,MSGL_V,"ASF: audio scrambling: %d x %d x %d\n",asf_scrambling_h,asf_scrambling_w,asf_scrambling_b);
+ //if(demuxer->audio->id==-1) demuxer->audio->id=streamh.stream_no & 0x7F;
+ break;
+ }
+ case ASF_GUID_PREFIX_video_stream: {
+ sh_video_t* sh_video=new_sh_video(demuxer,streamh.stream_no & 0x7F);
+ int len=streamh.type_size-(4+4+1+2);
+// sh_video->bih=malloc(chunksize); memset(sh_video->bih,0,chunksize);
+ sh_video->bih=calloc((len<sizeof(BITMAPINFOHEADER))?sizeof(BITMAPINFOHEADER):len,1);
+ memcpy(sh_video->bih,&buffer[4+4+1+2],len);
+ le2me_BITMAPINFOHEADER(sh_video->bih);
+ //sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale;
+ //sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
+ if(verbose>=1) print_video_header(sh_video->bih);
+ //asf_video_id=streamh.stream_no & 0x7F;
+ //if(demuxer->video->id==-1) demuxer->video->id=streamh.stream_no & 0x7F;
+ break;
+ }
+ }
+ // stream-specific data:
+ // stream_read(demuxer->stream,(char*) buffer,streamh.stream_size);
+ break;
+// case ASF_GUID_PREFIX_header_2_0: return "guid_header_2_0";
+ case ASF_GUID_PREFIX_file_header: // guid_file_header
+ stream_read(demuxer->stream,(char*) &fileh,sizeof(fileh));
+ le2me_ASF_file_header_t(&fileh);
+ mp_msg(MSGT_HEADER,MSGL_V,"ASF: packets: %d flags: %d pack_size: %d frame_size: %d\n",(int)fileh.packets,(int)fileh.flags,(int)fileh.packetsize,(int)fileh.frame_size);
+ asf_packetsize=fileh.packetsize;
+ asf_packet=malloc(asf_packetsize); // !!!
+ break;
+ case ASF_GUID_PREFIX_data_chunk: // guid_data_chunk
+ demuxer->movi_start=stream_tell(demuxer->stream)+26;
+ demuxer->movi_end=endpos;
+ mp_msg(MSGT_HEADER,MSGL_V,"Found movie at 0x%X - 0x%X\n",(int)demuxer->movi_start,(int)demuxer->movi_end);
+ break;
+
+// case ASF_GUID_PREFIX_index_chunk: return "guid_index_chunk";
+
+ case ASF_GUID_PREFIX_content_desc: // Content description
+ if(verbose){
+ char *string=NULL;
+ stream_read(demuxer->stream,(char*) &contenth,sizeof(contenth));
+ le2me_ASF_content_description_t(&contenth);
+ mp_msg(MSGT_HEADER,MSGL_V,"\n");
+ // extract the title
+ if( contenth.title_size!=0 ) {
+ string=(char*)malloc(contenth.title_size);
+ stream_read(demuxer->stream, string, contenth.title_size);
+ print_asf_string(" Title: ", string, contenth.title_size);
+ }
+ // extract the author
+ if( contenth.author_size!=0 ) {
+ string=(char*)realloc((void*)string, contenth.author_size);
+ stream_read(demuxer->stream, string, contenth.author_size);
+ print_asf_string(" Author: ", string, contenth.author_size);
+ }
+ // extract the copyright
+ if( contenth.copyright_size!=0 ) {
+ string=(char*)realloc((void*)string, contenth.copyright_size);
+ stream_read(demuxer->stream, string, contenth.copyright_size);
+ print_asf_string(" Copyright: ", string, contenth.copyright_size);
+ }
+ // extract the comment
+ if( contenth.comment_size!=0 ) {
+ string=(char*)realloc((void*)string, contenth.comment_size);
+ stream_read(demuxer->stream, string, contenth.comment_size);
+ print_asf_string(" Comment: ", string, contenth.comment_size);
+ }
+ // extract the rating
+ if( contenth.rating_size!=0 ) {
+ string=(char*)realloc((void*)string, contenth.rating_size);
+ stream_read(demuxer->stream, string, contenth.rating_size);
+ print_asf_string(" Rating: ", string, contenth.rating_size);
+ }
+ mp_msg(MSGT_HEADER,MSGL_V,"\n");
+ free(string);
+ }
+ break;
+
+ } // switch GUID
+
+ if(ASF_LOAD_GUID_PREFIX(objh.guid)==ASF_GUID_PREFIX_data_chunk) break; // movi chunk
+
+ if(!stream_seek(demuxer->stream,endpos)) break;
+} // while EOF
+
+#if 0
+if(verbose){
+ printf("ASF duration: %d\n",(int)fileh.duration);
+ printf("ASF start pts: %d\n",(int)fileh.start_timestamp);
+ printf("ASF end pts: %d\n",(int)fileh.end_timestamp);
+}
+#endif
+
+#endif
+return 1;
+}
diff --git a/libmpdemux/aviheader.c b/libmpdemux/aviheader.c
new file mode 100644
index 0000000000..a3c073185f
--- /dev/null
+++ b/libmpdemux/aviheader.c
@@ -0,0 +1,241 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "mp_msg.h"
+
+#include "stream.h"
+#include "demuxer.h"
+
+#include "wine/mmreg.h"
+#include "wine/avifmt.h"
+#include "wine/vfw.h"
+
+#include "codec-cfg.h"
+#include "bswap.h"
+#include "stheader.h"
+#include "aviheader.h"
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+
+static MainAVIHeader avih;
+
+extern void print_avih(MainAVIHeader *h);
+extern void print_avih_flags(MainAVIHeader *h);
+extern void print_strh(AVIStreamHeader *h);
+extern void print_wave_header(WAVEFORMATEX *h);
+extern void print_video_header(BITMAPINFOHEADER *h);
+extern void print_index(AVIINDEXENTRY *idx,int idx_size);
+
+void read_avi_header(demuxer_t *demuxer,int index_mode){
+sh_audio_t *sh_audio=NULL;
+sh_video_t *sh_video=NULL;
+int stream_id=-1;
+int idxfix_videostream=0;
+int idxfix_divx=0;
+avi_priv_t* priv=demuxer->priv;
+
+//---- AVI header:
+priv->idx_size=0;
+while(1){
+ int id=stream_read_dword_le(demuxer->stream);
+ int chunksize,size2;
+ static int last_fccType=0;
+ char* hdr=NULL;
+ //
+ if(stream_eof(demuxer->stream)) break;
+ //
+ if(id==mmioFOURCC('L','I','S','T')){
+ int len=stream_read_dword_le(demuxer->stream)-4; // list size
+ id=stream_read_dword_le(demuxer->stream); // list type
+ mp_msg(MSGT_HEADER,MSGL_DBG2,"LIST %.4s len=%d\n",(char *) &id,len);
+ if(id==listtypeAVIMOVIE){
+ // found MOVI header
+ demuxer->movi_start=stream_tell(demuxer->stream);
+ demuxer->movi_end=demuxer->movi_start+len;
+ mp_msg(MSGT_HEADER,MSGL_V,"Found movie at 0x%X - 0x%X\n",(int)demuxer->movi_start,(int)demuxer->movi_end);
+ if(index_mode==-2) break; // reading from non-seekable source (stdin)
+ len=(len+1)&(~1);
+ stream_skip(demuxer->stream,len);
+ }
+ continue;
+ }
+ size2=stream_read_dword_le(demuxer->stream);
+ mp_msg(MSGT_HEADER,MSGL_DBG2,"CHUNK %.4s len=%d\n",(char *) &id,size2);
+ chunksize=(size2+1)&(~1);
+ switch(id){
+ case mmioFOURCC('I','S','F','T'): hdr="Software";break;
+ case mmioFOURCC('I','N','A','M'): hdr="Name";break;
+ case mmioFOURCC('I','S','B','J'): hdr="Title";break;
+ case mmioFOURCC('I','A','R','T'): hdr="Author";break;
+ case mmioFOURCC('I','C','O','P'): hdr="Copyright";break;
+ case mmioFOURCC('I','C','M','T'): hdr="Comment";break;
+ case ckidAVIMAINHDR: // read 'avih'
+ stream_read(demuxer->stream,(char*) &avih,MIN(size2,sizeof(avih)));
+ le2me_MainAVIHeader(&avih); // swap to machine endian
+ chunksize-=MIN(size2,sizeof(avih));
+ if(verbose) print_avih(&avih); else print_avih_flags(&avih);
+ break;
+ case ckidSTREAMHEADER: { // read 'strh'
+ AVIStreamHeader h;
+ stream_read(demuxer->stream,(char*) &h,MIN(size2,sizeof(h)));
+ le2me_AVIStreamHeader(&h); // swap to machine endian
+ chunksize-=MIN(size2,sizeof(h));
+ ++stream_id;
+ if(h.fccType==streamtypeVIDEO){
+ sh_video=new_sh_video(demuxer,stream_id);
+ memcpy(&sh_video->video,&h,sizeof(h));
+ } else
+ if(h.fccType==streamtypeAUDIO){
+ sh_audio=new_sh_audio(demuxer,stream_id);
+ memcpy(&sh_audio->audio,&h,sizeof(h));
+ }
+ last_fccType=h.fccType;
+ if(verbose>=1) print_strh(&h);
+ break; }
+ case ckidSTREAMFORMAT: { // read 'strf'
+ if(last_fccType==streamtypeVIDEO){
+ sh_video->bih=calloc((chunksize<sizeof(BITMAPINFOHEADER))?sizeof(BITMAPINFOHEADER):chunksize,1);
+// sh_video->bih=malloc(chunksize); memset(sh_video->bih,0,chunksize);
+ mp_msg(MSGT_HEADER,MSGL_V,"found 'bih', %d bytes of %d\n",chunksize,sizeof(BITMAPINFOHEADER));
+ stream_read(demuxer->stream,(char*) sh_video->bih,chunksize);
+ le2me_BITMAPINFOHEADER(sh_video->bih); // swap to machine endian
+ if(verbose>=1) print_video_header(sh_video->bih);
+ chunksize=0;
+// sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale;
+// sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
+// if(demuxer->video->id==-1) demuxer->video->id=stream_id;
+ // IdxFix:
+ idxfix_videostream=stream_id;
+ switch(sh_video->bih->biCompression){
+ case mmioFOURCC('D', 'I', 'V', '3'):
+ case mmioFOURCC('d', 'i', 'v', '3'):
+ case mmioFOURCC('D', 'I', 'V', '4'):
+ case mmioFOURCC('d', 'i', 'v', '4'):
+ case mmioFOURCC('D', 'I', 'V', '5'):
+ case mmioFOURCC('d', 'i', 'v', '5'):
+ case mmioFOURCC('D', 'I', 'V', '6'):
+ case mmioFOURCC('d', 'i', 'v', '6'):
+ case mmioFOURCC('M', 'P', '4', '3'):
+ case mmioFOURCC('m', 'p', '4', '3'):
+ case mmioFOURCC('M', 'P', '4', '2'):
+ case mmioFOURCC('m', 'p', '4', '2'):
+ case mmioFOURCC('D', 'I', 'V', '2'):
+ case mmioFOURCC('A', 'P', '4', '1'):
+ idxfix_divx=1; // we can fix keyframes only for divx coded files!
+ }
+ } else
+ if(last_fccType==streamtypeAUDIO){
+ int wf_size = chunksize<sizeof(WAVEFORMATEX)?sizeof(WAVEFORMATEX):chunksize;
+ sh_audio->wf=calloc(wf_size,1);
+// sh_audio->wf=malloc(chunksize); memset(sh_audio->wf,0,chunksize);
+ mp_msg(MSGT_HEADER,MSGL_V,"found 'wf', %d bytes of %d\n",chunksize,sizeof(WAVEFORMATEX));
+ stream_read(demuxer->stream,(char*) sh_audio->wf,chunksize);
+ le2me_WAVEFORMATEX(sh_audio->wf);
+ if (sh_audio->wf->cbSize != 0 &&
+ wf_size < sizeof(WAVEFORMATEX)+sh_audio->wf->cbSize) {
+ sh_audio->wf=realloc(sh_audio->wf, sizeof(WAVEFORMATEX)+sh_audio->wf->cbSize);
+ }
+ chunksize=0;
+ if(verbose>=1) print_wave_header(sh_audio->wf);
+// if(demuxer->audio->id==-1) demuxer->audio->id=stream_id;
+ }
+ break;
+ }
+ case ckidAVINEWINDEX: if(index_mode){
+ int i;
+ priv->idx_size=size2>>4;
+ mp_msg(MSGT_HEADER,MSGL_V,"Reading INDEX block, %d chunks for %ld frames\n",
+ priv->idx_size,avih.dwTotalFrames);
+ priv->idx=malloc(priv->idx_size<<4);
+ stream_read(demuxer->stream,(char*)priv->idx,priv->idx_size<<4);
+ for (i = 0; i < priv->idx_size; i++) // swap index to machine endian
+ le2me_AVIINDEXENTRY((AVIINDEXENTRY*)priv->idx + i);
+ chunksize-=priv->idx_size<<4;
+ if(verbose>=2) print_index(priv->idx,priv->idx_size);
+ break;
+ }
+ }
+ if(hdr){
+ char buf[256];
+ int len=(size2<250)?size2:250;
+ stream_read(demuxer->stream,buf,len);
+ chunksize-=len;
+ buf[len]=0;
+ mp_msg(MSGT_HEADER,MSGL_V,"%-10s: %s\n",hdr,buf);
+ }
+ if(chunksize>0) stream_skip(demuxer->stream,chunksize); else
+ if(chunksize<0) mp_msg(MSGT_HEADER,MSGL_WARN,"chunksize=%d (id=%.4s)\n",chunksize,(char *) &id);
+
+}
+
+if(index_mode>=2 || (priv->idx_size==0 && index_mode==1)){
+ // build index for file:
+ stream_reset(demuxer->stream);
+ stream_seek(demuxer->stream,demuxer->movi_start);
+
+ priv->idx_pos=0;
+ priv->idx_size=0;
+ priv->idx=NULL;
+
+ while(1){
+ int id,len,skip;
+ AVIINDEXENTRY* idx;
+ unsigned char c;
+ demuxer->filepos=stream_tell(demuxer->stream);
+ if(demuxer->filepos>=demuxer->movi_end) break;
+ id=stream_read_dword_le(demuxer->stream);
+ len=stream_read_dword_le(demuxer->stream);
+ if(id==mmioFOURCC('L','I','S','T')){
+ id=stream_read_dword_le(demuxer->stream); // list type
+ continue;
+ }
+ if(stream_eof(demuxer->stream)) break;
+ if(!id || avi_stream_id(id)==100) goto skip_chunk; // bad ID (or padding?)
+
+ if(priv->idx_pos>=priv->idx_size){
+// priv->idx_size+=32;
+ priv->idx_size+=1024; // +16kB
+ priv->idx=realloc(priv->idx,priv->idx_size*sizeof(AVIINDEXENTRY));
+ if(!priv->idx){priv->idx_pos=0; break;} // error!
+ }
+ idx=&((AVIINDEXENTRY *)priv->idx)[priv->idx_pos++];
+ idx->ckid=id;
+ idx->dwFlags=AVIIF_KEYFRAME; // FIXME
+ idx->dwChunkOffset=demuxer->filepos;
+ idx->dwChunkLength=len;
+
+ c=stream_read_char(demuxer->stream);
+
+ // Fix keyframes for DivX files:
+ if(idxfix_divx)
+ if(avi_stream_id(id)==idxfix_videostream){
+ if(c&0x40) idx->dwFlags=0;
+ }
+
+ mp_dbg(MSGT_HEADER,MSGL_DBG2,"%08X %08X %.4s %02X %X\n",demuxer->filepos,id,(char *) &id,c,(unsigned int) idx->dwFlags);
+#if 0
+ { unsigned char tmp[64];
+ int i;
+ stream_read(demuxer->stream,tmp,64);
+ printf("%.4s",&id);
+ for(i=0;i<64;i++) printf(" %02X",tmp[i]);
+ printf("\n");
+ }
+#endif
+skip_chunk:
+ skip=(len+1)&(~1); // total bytes in this chunk
+ stream_seek(demuxer->stream,8+demuxer->filepos+skip);
+ }
+ priv->idx_size=priv->idx_pos;
+ mp_msg(MSGT_HEADER,MSGL_INFO,"AVI: Generated index table for %d chunks!\n",priv->idx_size);
+}
+
+}
+
+#undef MIN
+
+
diff --git a/libmpdemux/aviheader.h b/libmpdemux/aviheader.h
new file mode 100644
index 0000000000..d3d129b691
--- /dev/null
+++ b/libmpdemux/aviheader.h
@@ -0,0 +1,106 @@
+#ifndef _aviheader_h
+#define _aviheader_h
+
+//#include "config.h" /* get correct definition WORDS_BIGENDIAN */
+#include "bswap.h"
+
+/*
+ * Some macros to swap little endian structures read from an AVI file
+ * into machine endian format
+ */
+#ifdef WORDS_BIGENDIAN
+#define le2me_MainAVIHeader(h) { \
+ (h)->dwMicroSecPerFrame = le2me_32((h)->dwMicroSecPerFrame); \
+ (h)->dwMaxBytesPerSec = le2me_32((h)->dwMaxBytesPerSec); \
+ (h)->dwPaddingGranularity = le2me_32((h)->dwPaddingGranularity); \
+ (h)->dwFlags = le2me_32((h)->dwFlags); \
+ (h)->dwTotalFrames = le2me_32((h)->dwTotalFrames); \
+ (h)->dwInitialFrames = le2me_32((h)->dwInitialFrames); \
+ (h)->dwStreams = le2me_32((h)->dwStreams); \
+ (h)->dwSuggestedBufferSize = le2me_32((h)->dwSuggestedBufferSize); \
+ (h)->dwWidth = le2me_32((h)->dwWidth); \
+ (h)->dwHeight = le2me_32((h)->dwHeight); \
+}
+
+#define le2me_AVIStreamHeader(h) { \
+ (h)->fccType = le2me_32((h)->fccType); \
+ (h)->fccHandler = le2me_32((h)->fccHandler); \
+ (h)->dwFlags = le2me_32((h)->dwFlags); \
+ (h)->wPriority = le2me_16((h)->wPriority); \
+ (h)->wLanguage = le2me_16((h)->wLanguage); \
+ (h)->dwInitialFrames = le2me_32((h)->dwInitialFrames); \
+ (h)->dwScale = le2me_32((h)->dwScale); \
+ (h)->dwRate = le2me_32((h)->dwRate); \
+ (h)->dwStart = le2me_32((h)->dwStart); \
+ (h)->dwLength = le2me_32((h)->dwLength); \
+ (h)->dwSuggestedBufferSize = le2me_32((h)->dwSuggestedBufferSize); \
+ (h)->dwQuality = le2me_32((h)->dwQuality); \
+ (h)->dwSampleSize = le2me_32((h)->dwSampleSize); \
+ le2me_RECT(&(h)->rcFrame); \
+}
+#define le2me_RECT(h) { \
+ (h)->left = le2me_16((h)->left); \
+ (h)->top = le2me_16((h)->top); \
+ (h)->right = le2me_16((h)->right); \
+ (h)->bottom = le2me_16((h)->bottom); \
+}
+#define le2me_BITMAPINFOHEADER(h) { \
+ (h)->biSize = le2me_32((h)->biSize); \
+ (h)->biWidth = le2me_32((h)->biWidth); \
+ (h)->biHeight = le2me_32((h)->biHeight); \
+ (h)->biPlanes = le2me_16((h)->biPlanes); \
+ (h)->biBitCount = le2me_16((h)->biBitCount); \
+ (h)->biCompression = le2me_32((h)->biCompression); \
+ (h)->biSizeImage = le2me_32((h)->biSizeImage); \
+ (h)->biXPelsPerMeter = le2me_32((h)->biXPelsPerMeter); \
+ (h)->biYPelsPerMeter = le2me_32((h)->biYPelsPerMeter); \
+ (h)->biClrUsed = le2me_32((h)->biClrUsed); \
+ (h)->biClrImportant = le2me_32((h)->biClrImportant); \
+}
+#define le2me_WAVEFORMATEX(h) { \
+ (h)->wFormatTag = le2me_16((h)->wFormatTag); \
+ (h)->nChannels = le2me_16((h)->nChannels); \
+ (h)->nSamplesPerSec = le2me_32((h)->nSamplesPerSec); \
+ (h)->nAvgBytesPerSec = le2me_32((h)->nAvgBytesPerSec); \
+ (h)->nBlockAlign = le2me_16((h)->nBlockAlign); \
+ (h)->wBitsPerSample = le2me_16((h)->wBitsPerSample); \
+ (h)->cbSize = le2me_16((h)->cbSize); \
+}
+#define le2me_AVIINDEXENTRY(h) { \
+ (h)->ckid = le2me_32((h)->ckid); \
+ (h)->dwFlags = le2me_32((h)->dwFlags); \
+ (h)->dwChunkOffset = le2me_32((h)->dwChunkOffset); \
+ (h)->dwChunkLength = le2me_32((h)->dwChunkLength); \
+}
+#else
+#define le2me_MainAVIHeader(h) /**/
+#define le2me_AVIStreamHeader(h) /**/
+#define le2me_RECT(h) /**/
+#define le2me_BITMAPINFOHEADER(h) /**/
+#define le2me_WAVEFORMATEX(h) /**/
+#define le2me_AVIINDEXENTRY(h) /**/
+#endif
+
+
+#endif
+
+
+typedef struct {
+ // index stuff:
+ void* idx;
+ int idx_size;
+ int idx_pos;
+ int idx_pos_a;
+ int idx_pos_v;
+ int idx_offset; // ennyit kell hozzaadni az index offset ertekekhez
+ // interleaved PTS stuff:
+ int skip_video_frames;
+ float avi_audio_pts;
+ float avi_video_pts;
+ float pts_correction;
+ unsigned int pts_corr_bytes;
+ unsigned char pts_corrected;
+ unsigned char pts_has_video;
+} avi_priv_t;
+
+#define AVI_PRIV ((avi_priv_t*)(demuxer->priv))
diff --git a/libmpdemux/aviprint.c b/libmpdemux/aviprint.c
new file mode 100644
index 0000000000..c8fdceea15
--- /dev/null
+++ b/libmpdemux/aviprint.c
@@ -0,0 +1,102 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+//extern int verbose; // defined in mplayer.c
+
+#include "stream.h"
+#include "demuxer.h"
+
+#include "wine/mmreg.h"
+#include "wine/avifmt.h"
+#include "wine/vfw.h"
+
+//#include "codec-cfg.h"
+//#include "stheader.h"
+
+void print_avih_flags(MainAVIHeader *h){
+ printf("MainAVIHeader.dwFlags: (%ld)%s%s%s%s%s%s\n",h->dwFlags,
+ (h->dwFlags&AVIF_HASINDEX)?" HAS_INDEX":"",
+ (h->dwFlags&AVIF_MUSTUSEINDEX)?" MUST_USE_INDEX":"",
+ (h->dwFlags&AVIF_ISINTERLEAVED)?" IS_INTERLEAVED":"",
+ (h->dwFlags&AVIF_TRUSTCKTYPE)?" TRUST_CKTYPE":"",
+ (h->dwFlags&AVIF_WASCAPTUREFILE)?" WAS_CAPTUREFILE":"",
+ (h->dwFlags&AVIF_COPYRIGHTED)?" COPYRIGHTED":""
+ );
+}
+
+void print_avih(MainAVIHeader *h){
+ printf("======= AVI Header =======\n");
+ printf("us/frame: %ld (fps=%5.3f)\n",h->dwMicroSecPerFrame,1000000.0f/(float)h->dwMicroSecPerFrame);
+ printf("max bytes/sec: %ld\n",h->dwMaxBytesPerSec);
+ printf("padding: %ld\n",h->dwPaddingGranularity);
+ print_avih_flags(h);
+ printf("frames total: %ld initial: %ld\n",h->dwTotalFrames,h->dwInitialFrames);
+ printf("streams: %ld\n",h->dwStreams);
+ printf("Suggested BufferSize: %ld\n",h->dwSuggestedBufferSize);
+ printf("Size: %ld x %ld\n",h->dwWidth,h->dwHeight);
+}
+
+void print_strh(AVIStreamHeader *h){
+ printf("======= STREAM Header =======\n");
+ printf("Type: %.4s FCC: %.4s (%X)\n",(char *)&h->fccType,(char *)&h->fccHandler,(unsigned int)h->fccHandler);
+ printf("Flags: %ld\n",h->dwFlags);
+ printf("Priority: %d Language: %d\n",h->wPriority,h->wLanguage);
+ printf("InitialFrames: %ld\n",h->dwInitialFrames);
+ printf("Rate: %ld/%ld = %5.3f\n",h->dwRate,h->dwScale,(float)h->dwRate/(float)h->dwScale);
+ printf("Start: %ld Len: %ld\n",h->dwStart,h->dwLength);
+ printf("Suggested BufferSize: %ld\n",h->dwSuggestedBufferSize);
+ printf("Quality %ld\n",h->dwQuality);
+ printf("Sample size: %ld\n",h->dwSampleSize);
+}
+
+void print_wave_header(WAVEFORMATEX *h){
+
+ printf("======= WAVE Format =======\n");
+ printf("Format Tag: %d (0x%X)\n",h->wFormatTag,h->wFormatTag);
+ printf("Channels: %d\n",h->nChannels);
+ printf("Samplerate: %ld\n",h->nSamplesPerSec);
+ printf("avg byte/sec: %ld\n",h->nAvgBytesPerSec);
+ printf("Block align: %d\n",h->nBlockAlign);
+ printf("bits/sample: %d\n",h->wBitsPerSample);
+ printf("cbSize: %d\n",h->cbSize);
+}
+
+
+void print_video_header(BITMAPINFOHEADER *h){
+ printf("======= VIDEO Format ======\n");
+ printf(" biSize %ld\n", h->biSize);
+ printf(" biWidth %ld\n", h->biWidth);
+ printf(" biHeight %ld\n", h->biHeight);
+ printf(" biPlanes %d\n", h->biPlanes);
+ printf(" biBitCount %d\n", h->biBitCount);
+ printf(" biCompression %ld='%.4s'\n", h->biCompression, (char *)&h->biCompression);
+ printf(" biSizeImage %ld\n", h->biSizeImage);
+ printf("===========================\n");
+}
+
+
+void print_index(AVIINDEXENTRY *idx,int idx_size){
+ int i;
+ unsigned int pos[256];
+ unsigned int num[256];
+ for(i=0;i<256;i++) num[i]=pos[i]=0;
+ for(i=0;i<idx_size;i++){
+ int id=avi_stream_id(idx[i].ckid);
+ if(id<0 || id>255) id=255;
+ printf("%5d: %.4s %4X %08X len:%6ld pos:%7d->%7.3f %7d->%7.3f\n",i,
+ (char *)&idx[i].ckid,
+ (unsigned int)idx[i].dwFlags,
+ (unsigned int)idx[i].dwChunkOffset,
+// idx[i].dwChunkOffset+demuxer->movi_start,
+ idx[i].dwChunkLength,
+ pos[id],(float)pos[id]/18747.0f,
+ num[id],(float)num[id]/23.976f
+ );
+ pos[id]+=idx[i].dwChunkLength;
+ ++num[id];
+ }
+}
+
+
diff --git a/libmpdemux/aviwrite.c b/libmpdemux/aviwrite.c
new file mode 100644
index 0000000000..beb431af8b
--- /dev/null
+++ b/libmpdemux/aviwrite.c
@@ -0,0 +1,172 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "wine/mmreg.h"
+#include "wine/avifmt.h"
+#include "wine/vfw.h"
+
+extern char* encode_name;
+extern char* encode_index_name;
+
+void write_avi_chunk(FILE *f,unsigned int id,int len,void* data){
+
+fwrite(&id,4,1,f);
+fwrite(&len,4,1,f);
+if(len>0){
+ if(data){
+ // DATA
+ fwrite(data,len,1,f);
+ if(len&1){ // padding
+ unsigned char zerobyte=0;
+ fwrite(&zerobyte,1,1,f);
+ }
+ } else {
+ // JUNK
+ char *avi_junk_data="[= MPlayer junk data! =]";
+ if(len&1) ++len; // padding
+ while(len>0){
+ int l=strlen(avi_junk_data);
+ if(l>len) l=len;
+ fwrite(avi_junk_data,l,1,f);
+ len-=l;
+ }
+ }
+}
+
+}
+
+
+void write_avi_list(FILE *f,unsigned int id,int len){
+ unsigned int list_id=FOURCC_LIST;
+ len+=4; // list fix
+ fwrite(&list_id,4,1,f);
+ fwrite(&len,4,1,f);
+ fwrite(&id,4,1,f);
+}
+
+struct {
+ MainAVIHeader avih;
+ AVIStreamHeader video;
+ BITMAPINFOHEADER bih;
+ unsigned int movi_start;
+ unsigned int movi_end;
+ unsigned int file_end;
+} wah;
+
+void write_avi_header(FILE *f){
+ unsigned int riff[3];
+ // RIFF header:
+ riff[0]=mmioFOURCC('R','I','F','F');
+ riff[1]=wah.file_end; // filesize
+ riff[2]=formtypeAVI; // 'AVI '
+ fwrite(&riff,12,1,f);
+ // AVI header:
+ write_avi_list(f,listtypeAVIHEADER,sizeof(wah.avih)+8+12+sizeof(wah.video)+8+sizeof(wah.bih)+8);
+ write_avi_chunk(f,ckidAVIMAINHDR,sizeof(wah.avih),&wah.avih);
+ // stream header:
+ write_avi_list(f,listtypeSTREAMHEADER,sizeof(wah.video)+8+sizeof(wah.bih)+8);
+ write_avi_chunk(f,ckidSTREAMHEADER,sizeof(wah.video),&wah.video);
+ write_avi_chunk(f,ckidSTREAMFORMAT,sizeof(wah.bih),&wah.bih);
+ // JUNK:
+ write_avi_chunk(f,ckidAVIPADDING,2048-(ftell(f)&2047)-8,NULL);
+ // 'movi' header:
+ write_avi_list(f,listtypeAVIMOVIE,wah.movi_end-ftell(f)-12);
+ wah.movi_start=ftell(f);
+}
+
+// called _before_ encoding: (write placeholders and video info)
+void write_avi_header_1(FILE *f,int fcc,float fps,int width,int height){
+ int frames=8*3600*fps; // 8 hours
+
+ wah.file_end=
+ wah.movi_end=0x7f000000;
+
+ wah.avih.dwMicroSecPerFrame=1000000.0f/fps;
+ wah.avih.dwMaxBytesPerSec=fps*500000; // ?????
+ wah.avih.dwPaddingGranularity=1; // padding
+ wah.avih.dwFlags=AVIF_ISINTERLEAVED;
+ wah.avih.dwTotalFrames=frames;
+ wah.avih.dwInitialFrames=0;
+ wah.avih.dwStreams=1;
+ wah.avih.dwSuggestedBufferSize=0x10000; // 1MB
+ wah.avih.dwWidth=width;
+ wah.avih.dwHeight=height;
+ wah.avih.dwReserved[0]=
+ wah.avih.dwReserved[1]=
+ wah.avih.dwReserved[2]=
+ wah.avih.dwReserved[3]=0;
+
+ wah.video.fccType=streamtypeVIDEO;
+ wah.video.fccHandler=fcc;
+ wah.video.dwFlags=0;
+ wah.video.wPriority=0;
+ wah.video.wLanguage=0;
+ wah.video.dwInitialFrames=0;
+ wah.video.dwScale=10000;
+ wah.video.dwRate=fps*10000;
+ wah.video.dwStart=0;
+ wah.video.dwLength=frames;
+ wah.video.dwSuggestedBufferSize=0x100000; // 1MB ????
+ wah.video.dwQuality=10000;
+ wah.video.dwSampleSize=width*height*3;
+
+ wah.bih.biSize=sizeof(wah.bih); // 40 ?
+ wah.bih.biWidth=width;
+ wah.bih.biHeight=height;
+ wah.bih.biPlanes=1;
+ wah.bih.biBitCount=24;
+ wah.bih.biCompression=fcc;
+ wah.bih.biSizeImage=3*width*height;
+ wah.bih.biXPelsPerMeter=
+ wah.bih.biYPelsPerMeter=
+ wah.bih.biClrUsed=
+ wah.bih.biClrImportant=0;
+
+ write_avi_header(f);
+}
+
+void avi_fixate(){
+ // append index and fix avi headers:
+ FILE *f1=fopen(encode_name,"r+");
+ FILE *f2;
+
+ if(!f1) return; // error
+
+ fseek(f1,0,SEEK_END);
+ wah.file_end=wah.movi_end=ftell(f1);
+
+ // index:
+ if(encode_index_name && (f2=fopen(encode_index_name,"rb"))){
+ AVIINDEXENTRY idx;
+ unsigned int pos=0;
+ int frames=0;
+ write_avi_chunk(f1,ckidAVINEWINDEX,0,NULL);
+ while(fread(&idx,sizeof(idx),1,f2)>0){
+ idx.dwChunkOffset-=wah.movi_start-4;
+ fwrite(&idx,sizeof(idx),1,f1);
+ ++frames;
+ }
+ fclose(f2);
+ unlink(encode_index_name);
+ wah.file_end=ftell(f1);
+ // re-write idx1 length:
+ pos=wah.file_end-wah.movi_end-8;
+ fseek(f1,wah.movi_end+4,SEEK_SET);
+ fwrite(&pos,4,1,f1);
+ // fixup frames:
+ wah.avih.dwTotalFrames=frames;
+ wah.video.dwLength=frames;
+ }
+
+ // re-write avi header:
+ fseek(f1,0,SEEK_SET);
+ write_avi_header(f1);
+
+ fclose(f1);
+
+}
+
+
+
diff --git a/libmpdemux/bswap.h b/libmpdemux/bswap.h
new file mode 100644
index 0000000000..21072f676a
--- /dev/null
+++ b/libmpdemux/bswap.h
@@ -0,0 +1,2 @@
+/* Let it be for now*/
+#include "../bswap.h"
diff --git a/libmpdemux/codec-cfg.h b/libmpdemux/codec-cfg.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/libmpdemux/codec-cfg.h
diff --git a/libmpdemux/config.h b/libmpdemux/config.h
new file mode 100644
index 0000000000..319abb0131
--- /dev/null
+++ b/libmpdemux/config.h
@@ -0,0 +1,2 @@
+/* Let it be for now*/
+#include "../config.h"
diff --git a/libmpdemux/demux_asf.c b/libmpdemux/demux_asf.c
new file mode 100644
index 0000000000..94787171cb
--- /dev/null
+++ b/libmpdemux/demux_asf.c
@@ -0,0 +1,367 @@
+// ASF file parser for DEMUXER v0.3 by A'rpi/ESP-team
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "stream.h"
+#include "asf.h"
+#include "demuxer.h"
+
+
+/*
+ * Load 16/32-bit values in little endian byte order
+ * from an unaligned address
+ */
+#ifdef ARCH_X86
+#define LOAD_LE32(p) (*(unsigned int*)(p))
+#define LOAD_LE16(p) (*(unsigned short*)(p))
+#else
+#define LOAD_LE32(p) (((unsigned char*)(p))[0] | \
+ ((unsigned char*)(p))[1]<< 8 | \
+ ((unsigned char*)(p))[2]<<16 | \
+ ((unsigned char*)(p))[3]<<24 )
+#define LOAD_LE16(p) (((unsigned char*)(p))[0] | \
+ ((unsigned char*)(p))[1]<<8)
+#endif
+
+// defined at asfheader.c:
+extern unsigned char* asf_packet;
+extern int asf_scrambling_h;
+extern int asf_scrambling_w;
+extern int asf_scrambling_b;
+extern int asf_packetsize;
+
+
+// based on asf file-format doc by Eugene [http://divx.euro.ru]
+
+static void asf_descrambling(unsigned char *src,int len){
+ unsigned char *dst=malloc(len);
+ unsigned char *s2=src;
+ int i=0,x,y;
+ while(len-i>=asf_scrambling_h*asf_scrambling_w*asf_scrambling_b){
+// mp_msg(MSGT_DEMUX,MSGL_DBG4,"descrambling! (w=%d b=%d)\n",w,asf_scrambling_b);
+ //i+=asf_scrambling_h*asf_scrambling_w;
+ for(x=0;x<asf_scrambling_w;x++)
+ for(y=0;y<asf_scrambling_h;y++){
+ memcpy(dst+i,s2+(y*asf_scrambling_w+x)*asf_scrambling_b,asf_scrambling_b);
+ i+=asf_scrambling_b;
+ }
+ s2+=asf_scrambling_h*asf_scrambling_w*asf_scrambling_b;
+ }
+ //if(i<len) memcpy(dst+i,src+i,len-i);
+ memcpy(src,dst,i);
+ free(dst);
+}
+
+
+static int demux_asf_read_packet(demuxer_t *demux,unsigned char *data,int len,int id,int seq,unsigned long time,unsigned short dur,int offs,int keyframe){
+ demux_stream_t *ds=NULL;
+
+ mp_dbg(MSGT_DEMUX,MSGL_DBG4,"demux_asf.read_packet: id=%d seq=%d len=%d\n",id,seq,len);
+
+ if(demux->video->id==-1)
+ if(demux->v_streams[id])
+ demux->video->id=id;
+
+ if(demux->audio->id==-1)
+ if(demux->a_streams[id])
+ demux->audio->id=id;
+
+ if(id==demux->audio->id){
+ // audio
+ ds=demux->audio;
+ if(!ds->sh){
+ ds->sh=demux->a_streams[id];
+ mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected ASF audio ID = %d\n",ds->id);
+ }
+ } else
+ if(id==demux->video->id){
+ // video
+ ds=demux->video;
+ if(!ds->sh){
+ ds->sh=demux->v_streams[id];
+ mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected ASF video ID = %d\n",ds->id);
+ }
+ }
+
+ if(ds){
+ if(ds->asf_packet){
+ if(ds->asf_seq!=seq){
+ // closed segment, finalize packet:
+ if(ds==demux->audio)
+ if(asf_scrambling_h>1 && asf_scrambling_w>1)
+ asf_descrambling(ds->asf_packet->buffer,ds->asf_packet->len);
+ ds_add_packet(ds,ds->asf_packet);
+ ds->asf_packet=NULL;
+ } else {
+ // append data to it!
+ demux_packet_t* dp=ds->asf_packet;
+ if(dp->len!=offs && offs!=-1) mp_msg(MSGT_DEMUX,MSGL_V,"warning! fragment.len=%d BUT next fragment offset=%d \n",dp->len,offs);
+ dp->buffer=realloc(dp->buffer,dp->len+len);
+ memcpy(dp->buffer+dp->len,data,len);
+ mp_dbg(MSGT_DEMUX,MSGL_DBG4,"data appended! %d+%d\n",dp->len,len);
+ dp->len+=len;
+ // we are ready now.
+ return 1;
+ }
+ }
+ // create new packet:
+ { demux_packet_t* dp;
+ if(offs>0){
+ mp_msg(MSGT_DEMUX,MSGL_V,"warning! broken fragment, %d bytes missing \n",offs);
+ return 0;
+ }
+ dp=new_demux_packet(len);
+ memcpy(dp->buffer,data,len);
+ dp->pts=time*0.001f;
+ dp->flags=keyframe;
+// if(ds==demux->video) printf("ASF time: %8d dur: %5d \n",time,dur);
+ dp->pos=demux->filepos;
+ ds->asf_packet=dp;
+ ds->asf_seq=seq;
+ // we are ready now.
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+//static int num_elementary_packets100=0;
+//static int num_elementary_packets101=0;
+
+// return value:
+// 0 = EOF or no stream found
+// 1 = successfully read a packet
+int demux_asf_fill_buffer(demuxer_t *demux){
+
+ demux->filepos=stream_tell(demux->stream);
+ if(demux->filepos>=demux->movi_end){
+ demux->stream->eof=1;
+ return 0;
+ }
+
+ stream_read(demux->stream,asf_packet,asf_packetsize);
+ if(demux->stream->eof) return 0; // EOF
+
+ if(asf_packet[0]==0x82){
+ unsigned char flags=asf_packet[3];
+ unsigned char segtype=asf_packet[4];
+ unsigned char* p=&asf_packet[5];
+ unsigned char* p_end=p+asf_packetsize;
+ unsigned long time;
+ unsigned short duration;
+ int segs=1;
+ unsigned char segsizetype=0x80;
+ int seg;
+ int padding=0;
+ int plen;
+
+ if(verbose>1){
+ int i;
+ for(i=0;i<16;i++) printf(" %02X",asf_packet[i]);
+ printf("\n");
+ }
+
+ //if(segtype!=0x5d) printf("Warning! packet[4] != 0x5d \n");
+
+ // Calculate packet size (plen):
+ if(flags&0x40){
+ // Explicit (absoulte) packet size
+ plen=LOAD_LE16(p); p+=2;
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"Explicit packet size specified: %d \n",plen);
+ if(plen>asf_packetsize) mp_msg(MSGT_DEMUX,MSGL_V,"Warning! plen>packetsize! (%d>%d) \n",plen,asf_packetsize);
+ if(flags&(8|16)){
+ padding=p[0];p++;
+ if(flags&16){ padding|=p[0]<<8; p++;}
+ mp_msg(MSGT_DEMUX,MSGL_V,"Warning! explicit=%d padding=%d \n",plen,asf_packetsize-padding);
+ }
+ } else {
+ // Padding (relative) size
+ if(flags&8){
+ padding=p[0];++p;
+ } else
+ if(flags&16){
+ padding=LOAD_LE16(p);p+=2;
+ }
+ plen=asf_packetsize-padding;
+ }
+
+ time = LOAD_LE32(p); p+=4;
+ duration = LOAD_LE16(p); p+=2;
+ if(flags&1){
+ segsizetype=p[0] & 0xC0;
+ segs=p[0] & 0x3F;
+ ++p;
+ }
+ mp_dbg(MSGT_DEMUX,MSGL_DBG4,"%08X: flag=%02X segs=%d pad=%d time=%ld dur=%d\n",
+ demux->filepos,flags,segs,padding,time,duration);
+ for(seg=0;seg<segs;seg++){
+ //ASF_segmhdr_t* sh;
+ unsigned char streamno;
+ unsigned char seq;
+ int len;
+ unsigned long x;
+ unsigned char type;
+ unsigned long time2;
+ int keyframe=0;
+
+ if(p>=p_end) mp_msg(MSGT_DEMUX,MSGL_V,"Warning! invalid packet 1, sig11 coming soon...\n");
+
+ if(verbose>1){
+ int i;
+ printf("seg %d:",seg);
+ for(i=0;i<16;i++) printf(" %02X",p[i]);
+ printf("\n");
+ }
+
+ streamno=p[0]&0x7F;
+ if(p[0]&0x80) keyframe=1;
+ seq=p[1];
+ p+=2;
+
+ switch(segtype){
+ case 0x55:
+ x=*((unsigned char*)p);
+ p++;
+ break;
+ case 0x59:
+ x=LOAD_LE16(p);
+ p+=2;
+ break;
+ case 0x5D:
+ x=LOAD_LE32(p);
+ p+=4;
+ break;
+ default:
+ mp_msg(MSGT_DEMUX,MSGL_V,"Warning! unknown segtype == 0x%2X \n",segtype);
+ x=0;
+ }
+
+ type=p[0]; p++; // 0x01: grouping 0x08: single
+
+ switch(type){
+ case 0x01:
+ //printf("grouping: %02X \n",p[0]);
+ ++p; // skip unknown byte
+ break;
+ case 0x08:
+ //printf("!!! obj_length = %d\n",*((unsigned long*)p));
+ p+=4;
+ time2=LOAD_LE32(p);p+=4;
+ break;
+ default:
+ mp_msg(MSGT_DEMUX,MSGL_V,"unknown segment type: 0x%02X \n",type);
+ }
+
+ if(flags&1){
+ // multiple segments
+ if(segsizetype==0x40){
+ len=*((unsigned char*)p);p++; // 1 byte
+ } else {
+ len=LOAD_LE16(p);p+=2; // 2 byte
+ }
+ } else {
+ // single segment
+ len=plen-(p-asf_packet);
+ }
+ if(len<0 || (p+len)>=p_end){
+ mp_msg(MSGT_DEMUX,MSGL_V,"ASF_parser: warning! segment len=%d\n",len);
+ }
+ mp_dbg(MSGT_DEMUX,MSGL_DBG4," seg #%d: streamno=%d seq=%d type=%02X len=%d\n",seg,streamno,seq,type,len);
+
+ switch(type){
+ case 0x01:
+ // GROUPING:
+ //printf("ASF_parser: warning! grouping (flag=1) not yet supported!\n",len);
+ //printf(" total: %d \n",len);
+ while(len>0){
+ int len2=p[0];
+ p++;
+ //printf(" group part: %d bytes\n",len2);
+ demux_asf_read_packet(demux,p,len2,streamno,seq,x,duration,-1,keyframe);
+ p+=len2;
+ len-=len2+1;
+ }
+ if(len!=0){
+ mp_msg(MSGT_DEMUX,MSGL_V,"ASF_parser: warning! groups total != len\n");
+ }
+ break;
+ case 0x08:
+ // NO GROUPING:
+ //printf("fragment offset: %d \n",sh->x);
+ demux_asf_read_packet(demux,p,len,streamno,seq,time2,duration,x,keyframe);
+ p+=len;
+ break;
+ }
+
+ } // for segs
+ return 1; // success
+ }
+
+ mp_msg(MSGT_DEMUX,MSGL_V,"%08X: UNKNOWN TYPE %02X %02X %02X %02X %02X...\n",demux->filepos,asf_packet[0],asf_packet[1],asf_packet[2],asf_packet[3],asf_packet[4]);
+ return 0;
+}
+
+
+#include "wine/mmreg.h"
+#include "wine/avifmt.h"
+#include "wine/vfw.h"
+
+#include "codec-cfg.h"
+#include "stheader.h"
+
+
+void demux_seek_asf(demuxer_t *demuxer,float rel_seek_secs,int flags){
+ demux_stream_t *d_audio=demuxer->audio;
+ demux_stream_t *d_video=demuxer->video;
+ sh_audio_t *sh_audio=d_audio->sh;
+// sh_video_t *sh_video=d_video->sh;
+
+ //FIXME: OFF_T - didn't test ASF case yet (don't have a large asf...)
+ //FIXME: reports good or bad to steve@daviesfam.org please
+
+ //================= seek in ASF ==========================
+ float p_rate=10; // packets / sec
+ off_t rel_seek_packs=(flags&2)? // FIXME: int may be enough?
+ (rel_seek_secs*(demuxer->movi_end-demuxer->movi_start)/asf_packetsize):
+ (rel_seek_secs*p_rate);
+ off_t rel_seek_bytes=rel_seek_packs*asf_packetsize;
+ off_t newpos;
+ //printf("ASF: packs: %d duration: %d \n",(int)fileh.packets,*((int*)&fileh.duration));
+// printf("ASF_seek: %d secs -> %d packs -> %d bytes \n",
+// rel_seek_secs,rel_seek_packs,rel_seek_bytes);
+ newpos=((flags&1)?demuxer->movi_start:demuxer->filepos)+rel_seek_bytes;
+ if(newpos<0 || newpos<demuxer->movi_start) newpos=demuxer->movi_start;
+// printf("\r -- asf: newpos=%d -- \n",newpos);
+ stream_seek(demuxer->stream,newpos);
+
+ ds_fill_buffer(d_video);
+ if(sh_audio){
+ ds_fill_buffer(d_audio);
+ resync_audio_stream(sh_audio);
+ }
+
+ while(1){
+ if(sh_audio && !d_audio->eof){
+ float a_pts=d_audio->pts;
+ a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
+ // sync audio:
+ if (d_video->pts > a_pts){
+ skip_audio_frame(sh_audio);
+// if(!ds_fill_buffer(d_audio)) sh_audio=NULL; // skip audio. EOF?
+ continue;
+ }
+ }
+ if(d_video->flags&1) break; // found a keyframe!
+ if(!ds_fill_buffer(d_video)) break; // skip frame. EOF?
+ }
+
+
+}
+
diff --git a/libmpdemux/demux_avi.c b/libmpdemux/demux_avi.c
new file mode 100644
index 0000000000..1583371b48
--- /dev/null
+++ b/libmpdemux/demux_avi.c
@@ -0,0 +1,673 @@
+// AVI file parser for DEMUXER v2.9 by A'rpi/ESP-team
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "stream.h"
+#include "demuxer.h"
+
+#include "wine/mmreg.h"
+#include "wine/avifmt.h"
+#include "wine/vfw.h"
+
+#include "codec-cfg.h"
+#include "stheader.h"
+
+#include "aviheader.h"
+
+// Select ds from ID
+demux_stream_t* demux_avi_select_stream(demuxer_t *demux,unsigned int id){
+ int stream_id=avi_stream_id(id);
+
+// printf("demux_avi_select_stream(%d) {a:%d/v:%d}\n",stream_id,
+// demux->audio->id,demux->video->id);
+
+ if(demux->video->id==-1)
+ if(demux->v_streams[stream_id])
+ demux->video->id=stream_id;
+
+ if(demux->audio->id==-1)
+ if(demux->a_streams[stream_id])
+ demux->audio->id=stream_id;
+
+ if(stream_id==demux->audio->id){
+ if(!demux->audio->sh){
+ demux->audio->sh=demux->a_streams[stream_id];
+ mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected AVI audio ID = %d\n",demux->audio->id);
+ }
+ return demux->audio;
+ }
+ if(stream_id==demux->video->id){
+ if(!demux->video->sh){
+ demux->video->sh=demux->v_streams[stream_id];
+ mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected AVI video ID = %d\n",demux->video->id);
+ }
+ return demux->video;
+ }
+ if(id!=mmioFOURCC('J','U','N','K')){
+ // unknown
+ mp_msg(MSGT_DEMUX,MSGL_DBG2,"Unknown chunk: %.4s (%X)\n",(char *) &id,id);
+ }
+ return NULL;
+}
+
+static int demux_avi_read_packet(demuxer_t *demux,unsigned int id,unsigned int len,int idxpos,int flags){
+ avi_priv_t *priv=demux->priv;
+ int skip;
+ float pts=0;
+ demux_stream_t *ds=demux_avi_select_stream(demux,id);
+
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3,"demux_avi.read_packet: %X\n",id);
+
+ if(ds==demux->audio){
+
+ if(priv->pts_corrected==0){
+// printf("\rYYY-A A: %5.3f V: %5.3f \n",priv->avi_audio_pts,priv->avi_video_pts);
+ if(priv->pts_has_video){
+ // we have video pts now
+ float delay=(float)priv->pts_corr_bytes/((sh_audio_t*)(ds->sh))->wf->nAvgBytesPerSec;
+ mp_msg(MSGT_DEMUX,MSGL_V,"XXX initial v_pts=%5.3f a_pos=%d (%5.3f) \n",priv->avi_audio_pts,priv->pts_corr_bytes,delay);
+ //priv->pts_correction=-priv->avi_audio_pts+delay;
+ priv->pts_correction=delay-priv->avi_audio_pts;
+ priv->avi_audio_pts+=priv->pts_correction;
+ priv->pts_corrected=1;
+ } else
+ priv->pts_corr_bytes+=len;
+ }
+ pts=priv->avi_audio_pts; //+priv->pts_correction;
+ priv->avi_audio_pts=0;
+ } else
+ if(ds==demux->video){
+ // video
+ if(priv->skip_video_frames>0){
+ // drop frame (seeking)
+ --priv->skip_video_frames;
+ ds=NULL;
+// } else {
+// pts=priv->avi_video_pts;
+ }
+ // ezt a 2 sort lehet hogy fell kell majd cserelni:
+ //priv->avi_video_pts+=avi_pts_frametime;
+ //priv->avi_video_pts+=(float)avi_header.video.dwScale/(float)avi_header.video.dwRate;
+ //priv->avi_video_pts+=((sh_video_t*)ds->sh)->frametime;
+// FIXME!!!
+#if 1
+// printf("ds=0x%X\n",ds);
+// printf("packno=%d\n",ds->pack_no);
+// printf("### pack_no=%d\n",demux->video->pack_no+demux->video->packs);
+ priv->avi_video_pts = (demux->video->pack_no+demux->video->packs) *
+ (float)((sh_video_t*)demux->video->sh)->video.dwScale /
+ (float)((sh_video_t*)demux->video->sh)->video.dwRate;
+#else
+ priv->avi_video_pts+=(float)((sh_video_t*)(demux->video->sh))->video.dwScale/(float)((sh_video_t*)(demux->video->sh))->video.dwRate;
+// priv->avi_video_pts+=avi_video_ftime;
+#endif
+// printf("\rYYY-V A: %5.3f V: %5.3f \n",priv->avi_audio_pts,priv->avi_video_pts);
+ priv->avi_audio_pts=priv->avi_video_pts+priv->pts_correction;
+ priv->pts_has_video=1;
+
+ pts=priv->avi_video_pts;
+
+ //printf("read pack_no: %d pts %5.3f \n",demux->video->pack_no+demux->video->packs,pts);
+
+ }
+
+// len=stream_read_dword_le(demux->stream);
+ skip=(len+1)&(~1); // total bytes in this chunk
+
+ if(ds){
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_AVI: Read %d data bytes from packet %04X\n",len,id);
+ ds_read_packet(ds,demux->stream,len,pts,idxpos,flags);
+ skip-=len;
+ }
+ if(skip){
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_AVI: Skipping %d bytes from packet %04X\n",skip,id);
+ stream_skip(demux->stream,skip);
+ }
+ return ds?1:0;
+}
+
+// return value:
+// 0 = EOF or no stream found
+// 1 = successfully read a packet
+int demux_avi_fill_buffer(demuxer_t *demux){
+avi_priv_t *priv=demux->priv;
+unsigned int id=0;
+unsigned int len;
+int max_packs=128;
+int ret=0;
+
+do{
+ int flags=0;
+ AVIINDEXENTRY *idx=NULL;
+#if 0
+ demux->filepos=stream_tell(demux->stream);
+ if(demux->filepos>=demux->movi_end){
+ demux->stream->eof=1;
+ return 0;
+ }
+ if(stream_eof(demux->stream)) return 0;
+#endif
+ if(priv->idx_size>0 && priv->idx_pos<priv->idx_size){
+ unsigned int pos;
+
+ //if(priv->idx_pos<0) printf("Fatal! idx_pos=%d\n",priv->idx_pos);
+
+ idx=&((AVIINDEXENTRY *)priv->idx)[priv->idx_pos++];
+
+ //printf("[%d]",priv->idx_pos);fflush(stdout);
+
+ //stream_seek(demux->stream,idx.dwChunkOffset);
+ //printf("IDX pos=%X idx.pos=%X idx.size=%X idx.flags=%X\n",demux->filepos,
+ // pos-4,idx->dwChunkLength,idx->dwFlags);
+ if(idx->dwFlags&AVIIF_LIST){
+ // LIST
+ continue;
+ }
+ if(!demux_avi_select_stream(demux,idx->ckid)){
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3,"Skip chunk %.4s (0x%X) \n",(char *)&idx->ckid,(unsigned int)idx->ckid);
+ continue; // skip this chunk
+ }
+
+ pos=idx->dwChunkOffset+priv->idx_offset;
+ if(pos<demux->movi_start || pos>=demux->movi_end){
+ mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! idx=0x%X \n",pos);
+ continue;
+ }
+#if 0
+ if(pos!=demux->filepos){
+ mp_msg(MSGT_DEMUX,MSGL_V,"Warning! pos=0x%X idx.pos=0x%X diff=%d \n",demux->filepos,pos,pos-demux->filepos);
+ }
+#endif
+ stream_seek(demux->stream,pos);
+ demux->filepos=stream_tell(demux->stream);
+ id=stream_read_dword_le(demux->stream);
+ if(stream_eof(demux->stream)) return 0; // EOF!
+
+ if(id!=idx->ckid){
+ mp_msg(MSGT_DEMUX,MSGL_V,"ChunkID mismatch! raw=%.4s idx=%.4s \n",(char *)&id,(char *)&idx->ckid);
+ id=idx->ckid;
+// continue;
+ }
+ len=stream_read_dword_le(demux->stream);
+// if((len&(~1))!=(idx->dwChunkLength&(~1))){
+// if((len)!=(idx->dwChunkLength)){
+ if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){
+ mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%ld \n",len,idx->dwChunkLength);
+ len=idx->dwChunkLength;
+// continue;
+ }
+ if(idx->dwFlags&AVIIF_KEYFRAME) flags=1;
+ } else {
+ demux->filepos=stream_tell(demux->stream);
+ if(demux->filepos>=demux->movi_end){
+ demux->stream->eof=1;
+ return 0;
+ }
+ id=stream_read_dword_le(demux->stream);
+ len=stream_read_dword_le(demux->stream);
+ if(stream_eof(demux->stream)) return 0; // EOF!
+
+ if(id==mmioFOURCC('L','I','S','T')){
+ id=stream_read_dword_le(demux->stream); // list type
+ continue;
+ }
+ }
+ ret=demux_avi_read_packet(demux,id,len,priv->idx_pos-1,flags);
+// if(!ret && priv->skip_video_frames<=0)
+// if(--max_packs==0){
+// demux->stream->eof=1;
+// mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_DoesntContainSelectedStream);
+// return 0;
+// }
+} while(ret!=1);
+ return 1;
+}
+
+
+// return value:
+// 0 = EOF or no stream found
+// 1 = successfully read a packet
+int demux_avi_fill_buffer_ni(demuxer_t *demux,demux_stream_t* ds){
+avi_priv_t *priv=demux->priv;
+unsigned int id=0;
+unsigned int len;
+int max_packs=128;
+int ret=0;
+
+do{
+ int flags=0;
+ AVIINDEXENTRY *idx=NULL;
+ int idx_pos=0;
+ demux->filepos=stream_tell(demux->stream);
+
+ if(ds==demux->video) idx_pos=priv->idx_pos_v++; else
+ if(ds==demux->audio) idx_pos=priv->idx_pos_a++; else
+ idx_pos=priv->idx_pos++;
+
+ if(priv->idx_size>0 && idx_pos<priv->idx_size){
+ unsigned int pos;
+ idx=&((AVIINDEXENTRY *)priv->idx)[idx_pos];
+// idx=&priv->idx[idx_pos];
+
+ if(idx->dwFlags&AVIIF_LIST){
+ // LIST
+ continue;
+ }
+ if(ds && demux_avi_select_stream(demux,idx->ckid)!=ds){
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3,"Skip chunk %.4s (0x%X) \n",(char *)&idx->ckid,(unsigned int)idx->ckid);
+ continue; // skip this chunk
+ }
+
+ pos=idx->dwChunkOffset+priv->idx_offset;
+ if(pos<demux->movi_start || pos>=demux->movi_end){
+ mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! current=0x%X idx=0x%X \n",demux->filepos,pos);
+ continue;
+ }
+#if 0
+ if(pos!=demux->filepos){
+ mp_msg(MSGT_DEMUX,MSGL_V,"Warning! pos=0x%X idx.pos=0x%X diff=%d \n",demux->filepos,pos,pos-demux->filepos);
+ }
+#endif
+ stream_seek(demux->stream,pos);
+
+ id=stream_read_dword_le(demux->stream);
+
+ if(stream_eof(demux->stream)) return 0;
+
+ if(id!=idx->ckid){
+ mp_msg(MSGT_DEMUX,MSGL_V,"ChunkID mismatch! raw=%.4s idx=%.4s \n",(char *)&id,(char *)&idx->ckid);
+ id=idx->ckid;
+// continue;
+ }
+ len=stream_read_dword_le(demux->stream);
+// if((len&(~1))!=(idx->dwChunkLength&(~1))){
+// if((len)!=(idx->dwChunkLength)){
+ if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){
+ mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%ld \n",len,idx->dwChunkLength);
+ len=idx->dwChunkLength;
+// continue;
+ }
+ if(idx->dwFlags&AVIIF_KEYFRAME) flags=1;
+ } else return 0;
+ ret=demux_avi_read_packet(demux,id,len,idx_pos,flags);
+// if(!ret && priv->skip_video_frames<=0)
+// if(--max_packs==0){
+// demux->stream->eof=1;
+// mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_DoesntContainSelectedStream);
+// return 0;
+// }
+} while(ret!=1);
+ return 1;
+}
+
+
+// return value:
+// 0 = EOF or no stream found
+// 1 = successfully read a packet
+int demux_avi_fill_buffer_nini(demuxer_t *demux,demux_stream_t* ds){
+avi_priv_t *priv=demux->priv;
+unsigned int id=0;
+unsigned int len;
+int ret=0;
+int *fpos=NULL;
+
+ if(ds==demux->video) fpos=&priv->idx_pos_v; else
+ if(ds==demux->audio) fpos=&priv->idx_pos_a; else
+ return 0;
+
+ stream_seek(demux->stream,fpos[0]);
+
+do{
+
+ demux->filepos=stream_tell(demux->stream);
+ if(demux->filepos>=demux->movi_end){
+ demux->stream->eof=1;
+ return 0;
+ }
+ if(stream_eof(demux->stream)) return 0;
+
+ id=stream_read_dword_le(demux->stream);
+ len=stream_read_dword_le(demux->stream);
+ if(id==mmioFOURCC('L','I','S','T')){
+ id=stream_read_dword_le(demux->stream); // list type
+ continue;
+ }
+
+ if(ds==demux_avi_select_stream(demux,id)){
+ // read it!
+ ret=demux_avi_read_packet(demux,id,len,priv->idx_pos-1,0);
+ } else {
+ // skip it!
+ int skip=(len+1)&(~1); // total bytes in this chunk
+ stream_skip(demux->stream,skip);
+ }
+
+} while(ret!=1);
+ fpos[0]=stream_tell(demux->stream);
+ return 1;
+}
+
+//extern int audio_id;
+//extern int video_id;
+extern int index_mode; // -1=untouched 0=don't use index 1=use (geneate) index
+extern int force_ni;
+extern int pts_from_bps;
+
+void read_avi_header(demuxer_t *demuxer,int index_mode);
+
+demuxer_t* demux_open_avi(demuxer_t* demuxer){
+ demux_stream_t *d_audio=demuxer->audio;
+ demux_stream_t *d_video=demuxer->video;
+ sh_audio_t *sh_audio=NULL;
+ sh_video_t *sh_video=NULL;
+ avi_priv_t* priv=malloc(sizeof(avi_priv_t));
+
+ // priv struct:
+ priv->avi_audio_pts=priv->avi_video_pts=0.0f;
+ priv->pts_correction=0.0f;
+ priv->skip_video_frames=0;
+ priv->pts_corr_bytes=0;
+ priv->pts_has_video=priv->pts_corrected=0;
+ demuxer->priv=(void*)priv;
+
+ //---- AVI header:
+ read_avi_header(demuxer,(demuxer->stream->type!=STREAMTYPE_STREAM)?index_mode:-2);
+ stream_reset(demuxer->stream);
+ stream_seek(demuxer->stream,demuxer->movi_start);
+ priv->idx_pos=0;
+ priv->idx_pos_a=0;
+ priv->idx_pos_v=0;
+ if(priv->idx_size>0){
+ // decide index format:
+ if(((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset<demuxer->movi_start)
+ priv->idx_offset=demuxer->movi_start-4;
+ else
+ priv->idx_offset=0;
+ mp_msg(MSGT_DEMUX,MSGL_V,"AVI index offset: %d\n",priv->idx_offset);
+ }
+// demuxer->endpos=avi_header.movi_end;
+
+ if(priv->idx_size>0){
+ // check that file is non-interleaved:
+ int i;
+ int a_pos=-1;
+ int v_pos=-1;
+ for(i=0;i<priv->idx_size;i++){
+ AVIINDEXENTRY* idx=&((AVIINDEXENTRY *)priv->idx)[i];
+ demux_stream_t* ds=demux_avi_select_stream(demuxer,idx->ckid);
+ int pos=idx->dwChunkOffset+priv->idx_offset;
+ if(a_pos==-1 && ds==demuxer->audio){
+ a_pos=pos;
+ if(v_pos!=-1) break;
+ }
+ if(v_pos==-1 && ds==demuxer->video){
+ v_pos=pos;
+ if(a_pos!=-1) break;
+ }
+ }
+ if(v_pos==-1){
+ mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI_NI: " MSGTR_MissingVideoStream);
+ return NULL;
+// GUI_MSG( mplErrorAVINI )
+ }
+ if(a_pos==-1){
+ mp_msg(MSGT_DEMUX,MSGL_INFO,"AVI_NI: " MSGTR_MissingAudioStream);
+ sh_audio=NULL;
+ } else {
+ if(force_ni || abs(a_pos-v_pos)>0x100000){ // distance > 1MB
+ mp_msg(MSGT_DEMUX,MSGL_INFO,MSGTR_NI_Message,force_ni?MSGTR_NI_Forced:MSGTR_NI_Detected);
+ demuxer->type=DEMUXER_TYPE_AVI_NI; // HACK!!!!
+ pts_from_bps=1; // force BPS sync!
+ }
+ }
+ } else {
+ // no index
+ if(force_ni){
+ mp_msg(MSGT_DEMUX,MSGL_INFO,MSGTR_UsingNINI);
+ demuxer->type=DEMUXER_TYPE_AVI_NINI; // HACK!!!!
+ priv->idx_pos_a=
+ priv->idx_pos_v=demuxer->movi_start;
+ pts_from_bps=1; // force BPS sync!
+ }
+ demuxer->seekable=0;
+ }
+ if(!ds_fill_buffer(d_video)){
+ mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI: " MSGTR_MissingVideoStreamBug);
+ return NULL;
+// GUI_MSG( mplAVIErrorMissingVideoStream )
+ }
+ sh_video=d_video->sh;sh_video->ds=d_video;
+ if(d_audio->id!=-2){
+ mp_msg(MSGT_DEMUX,MSGL_V,"AVI: Searching for audio stream (id:%d)\n",d_audio->id);
+ if(!ds_fill_buffer(d_audio)){
+ mp_msg(MSGT_DEMUX,MSGL_INFO,"AVI: " MSGTR_MissingAudioStream);
+ sh_audio=NULL;
+ } else {
+ sh_audio=d_audio->sh;sh_audio->ds=d_audio;
+ sh_audio->format=sh_audio->wf->wFormatTag;
+ }
+ }
+ // calc. FPS:
+ sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale;
+ sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
+ // calculating video bitrate:
+ sh_video->i_bps=demuxer->movi_end-demuxer->movi_start-priv->idx_size*8;
+ if(sh_audio) sh_video->i_bps-=sh_audio->audio.dwLength;
+ mp_msg(MSGT_DEMUX,MSGL_V,"AVI video length=%d\n",sh_video->i_bps);
+ sh_video->i_bps=((float)sh_video->i_bps/(float)sh_video->video.dwLength)*sh_video->fps;
+ mp_msg(MSGT_DEMUX,MSGL_INFO,"VIDEO: [%.4s] %ldx%ld %dbpp %4.2f fps %5.1f kbps (%4.1f kbyte/s)\n",
+ (char *)&sh_video->bih->biCompression,
+ sh_video->bih->biWidth,
+ sh_video->bih->biHeight,
+ sh_video->bih->biBitCount,
+ sh_video->fps,
+ sh_video->i_bps*0.008f,
+ sh_video->i_bps/1024.0f );
+
+ return demuxer;
+
+}
+
+//extern float initial_pts_delay;
+
+void demux_seek_avi(demuxer_t *demuxer,float rel_seek_secs,int flags){
+ avi_priv_t *priv=demuxer->priv;
+ demux_stream_t *d_audio=demuxer->audio;
+ demux_stream_t *d_video=demuxer->video;
+ sh_audio_t *sh_audio=d_audio->sh;
+ sh_video_t *sh_video=d_video->sh;
+ float skip_audio_secs=0;
+
+ //FIXME: OFF_T - Didn't check AVI case yet (avi files can't be >2G anyway?)
+ //================= seek in AVI ==========================
+ int rel_seek_frames=rel_seek_secs*sh_video->fps;
+ int video_chunk_pos=d_video->pos;
+ int i;
+
+ if(flags&1){
+ // seek absolute
+ video_chunk_pos=0;
+ }
+
+ if(flags&2){
+ // float 0..1
+ int total=sh_video->video.dwLength;
+ if(total<=1){
+ // bad video header, try to get it from audio
+ if(sh_audio) total=sh_video->fps*sh_audio->audio.dwLength/sh_audio->wf->nAvgBytesPerSec;
+ if(total<=1){
+ mp_msg(MSGT_SEEK,MSGL_WARN,MSGTR_CouldntDetFNo);
+ total=0;
+ }
+ }
+ rel_seek_frames=rel_seek_secs*total;
+ }
+
+ priv->skip_video_frames=0;
+ priv->avi_audio_pts=0;
+
+// ------------ STEP 1: find nearest video keyframe chunk ------------
+ // find nearest video keyframe chunk pos:
+ if(rel_seek_frames>0){
+ // seek forward
+ while(video_chunk_pos<priv->idx_size){
+ int id=((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].ckid;
+ if(avi_stream_id(id)==d_video->id){ // video frame
+ if((--rel_seek_frames)<0 && ((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break;
+ }
+ ++video_chunk_pos;
+ }
+ } else {
+ // seek backward
+ while(video_chunk_pos>0){
+ int id=((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].ckid;
+ if(avi_stream_id(id)==d_video->id){ // video frame
+ if((++rel_seek_frames)>0 && ((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break;
+ }
+ --video_chunk_pos;
+ }
+ }
+ priv->idx_pos_a=priv->idx_pos_v=priv->idx_pos=video_chunk_pos;
+
+ // re-calc video pts:
+ d_video->pack_no=0;
+ for(i=0;i<video_chunk_pos;i++){
+ int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;
+ if(avi_stream_id(id)==d_video->id) ++d_video->pack_no;
+ }
+ sh_video->num_frames=sh_video->num_frames_decoded=d_video->pack_no;
+ priv->avi_video_pts=d_video->pack_no*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
+ d_video->pos=video_chunk_pos;
+
+ mp_msg(MSGT_SEEK,MSGL_DBG2,"V_SEEK: pack=%d pts=%5.3f chunk=%d \n",d_video->pack_no,priv->avi_video_pts,video_chunk_pos);
+
+// ------------ STEP 2: seek audio, find the right chunk & pos ------------
+
+ d_audio->pack_no=0;
+ d_audio->dpos=0;
+
+ if(sh_audio){
+ int i;
+// int apos=0;
+ int last=0;
+ int len=0;
+ int skip_audio_bytes=0;
+ int curr_audio_pos=-1;
+ int audio_chunk_pos=-1;
+ int chunk_max=(demuxer->type==DEMUXER_TYPE_AVI)?video_chunk_pos:priv->idx_size;
+
+ if(sh_audio->audio.dwSampleSize){
+ // constant rate audio stream
+#if 0
+ int align;
+ curr_audio_pos=(priv->avi_video_pts) * sh_audio->wf->nAvgBytesPerSec;
+ if(curr_audio_pos<0)curr_audio_pos=0;
+ align=sh_audio->audio.dwSampleSize;
+ if(sh_audio->wf->nBlockAlign>align) align=sh_audio->wf->nBlockAlign;
+ curr_audio_pos/=align;
+ curr_audio_pos*=align;
+#else
+ curr_audio_pos=(priv->avi_video_pts)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale;
+ curr_audio_pos*=sh_audio->audio.dwSampleSize;
+#endif
+
+ // find audio chunk pos:
+ for(i=0;i<chunk_max;i++){
+ int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;
+ if(avi_stream_id(id)==d_audio->id){
+ len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength;
+ audio_chunk_pos=i; ++d_audio->pack_no;
+ if(d_audio->dpos<=curr_audio_pos && curr_audio_pos<(d_audio->dpos+len)){
+ //if(verbose)printf("break;\n");
+ break;
+ }
+ d_audio->dpos+=len;
+ }
+ }
+ skip_audio_bytes=curr_audio_pos-d_audio->dpos;
+
+ } else {
+ // VBR audio
+ int chunks=(priv->avi_video_pts)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale;
+ audio_chunk_pos=0;
+
+ // find audio chunk pos:
+ for(i=0;i<priv->idx_size && chunks>0;i++){
+ int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;
+ if(avi_stream_id(id)==d_audio->id){
+ len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength;
+ if(i>chunk_max){
+ skip_audio_bytes+=len;
+ } else {
+ ++d_audio->pack_no;
+ d_audio->dpos+=len;
+ audio_chunk_pos=i;
+ }
+ --chunks;
+ }
+ }
+ //if(audio_chunk_pos>chunk_max) audio_chunk_pos=chunk_max;
+
+// printf("VBR seek: %5.3f -> chunk_no %d -> chunk_idx %d + skip %d \n",
+// priv->avi_video_pts, audio_chunk_pos, );
+
+ }
+
+ // Now we have:
+ // audio_chunk_pos = chunk no in index table (it's <=chunk_max)
+ // skip_audio_bytes = bytes to be skipped after chunk seek
+ // d-audio->pack_no = chunk_no in stream at audio_chunk_pos
+ // d_audio->dpos = bytepos in stream at audio_chunk_pos
+ // let's seek!
+
+ // update stream position:
+ d_audio->pos=audio_chunk_pos;
+// d_audio->dpos=apos;
+// d_audio->pts=initial_pts_delay+(float)apos/(float)sh_audio->wf->nAvgBytesPerSec;
+
+ if(demuxer->type==DEMUXER_TYPE_AVI){
+ // interleaved stream:
+ if(audio_chunk_pos<video_chunk_pos){
+ // calc priv->skip_video_frames & adjust video pts counter:
+ for(i=audio_chunk_pos;i<video_chunk_pos;i++){
+ int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;
+ if(avi_stream_id(id)==d_video->id) ++priv->skip_video_frames;
+ }
+ // requires for correct audio pts calculation (demuxer):
+ priv->avi_video_pts-=priv->skip_video_frames*(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
+ priv->idx_pos_a=priv->idx_pos_v=priv->idx_pos=audio_chunk_pos;
+ }
+ } else {
+ // non-interleaved stream:
+ priv->idx_pos_a=audio_chunk_pos;
+ priv->idx_pos_v=video_chunk_pos;
+ priv->idx_pos=(audio_chunk_pos<video_chunk_pos)?audio_chunk_pos:video_chunk_pos;
+ }
+
+
+
+ mp_msg(MSGT_SEEK,MSGL_V,"SEEK: idx=%d (a:%d v:%d) v.skip=%d a.skip=%d/%4.3f \n",
+ priv->idx_pos,audio_chunk_pos,video_chunk_pos,
+ priv->skip_video_frames,skip_audio_bytes,skip_audio_secs);
+
+ if(skip_audio_bytes){
+ demux_read_data(d_audio,NULL,skip_audio_bytes);
+ //d_audio->pts=0; // PTS is outdated because of the raw data skipping
+ }
+ resync_audio_stream(sh_audio);
+
+// sh_audio->timer=-skip_audio_secs;
+
+ }
+ d_video->pts=priv->avi_video_pts; // OSD
+
+}
+
+
+
diff --git a/libmpdemux/demux_mov.c b/libmpdemux/demux_mov.c
new file mode 100644
index 0000000000..76b85c9473
--- /dev/null
+++ b/libmpdemux/demux_mov.c
@@ -0,0 +1,613 @@
+// QuickTime MOV file parser by A'rpi
+// based on TOOLS/movinfo.c by me & Al3x
+// compressed header support from moov.c of the openquicktime lib.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+
+#ifdef HAVE_PNG
+// should be detected by ./configure...
+#define HAVE_ZLIB
+#endif
+
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "stream.h"
+#include "demuxer.h"
+
+#include "wine/mmreg.h"
+#include "wine/avifmt.h"
+#include "wine/vfw.h"
+
+#include "codec-cfg.h"
+#include "stheader.h"
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
+typedef struct {
+ unsigned int pts; // duration
+ unsigned int size;
+ off_t pos;
+} mov_sample_t;
+
+typedef struct {
+ unsigned int sample; // number of the first sample in teh chunk
+ unsigned int size; // number of samples in the chunk
+ int desc; // for multiple codecs mode - not used
+ off_t pos;
+} mov_chunk_t;
+
+typedef struct {
+ unsigned int first;
+ unsigned int spc;
+ unsigned int sdid;
+} mov_chunkmap_t;
+
+typedef struct {
+ unsigned int num;
+ unsigned int dur;
+} mov_durmap_t;
+
+typedef struct {
+ int id;
+ int type;
+ int pos;
+ //
+ int timescale;
+ unsigned int length;
+ int samplesize; // 0 = variable
+ int duration; // 0 = variable
+ int width,height; // for video
+ unsigned int fourcc;
+ //
+ int tkdata_len; // track data
+ unsigned char* tkdata;
+ int stdata_len; // stream data
+ unsigned char* stdata;
+ int samples_size;
+ mov_sample_t* samples;
+ int chunks_size;
+ mov_chunk_t* chunks;
+ int chunkmap_size;
+ mov_chunkmap_t* chunkmap;
+ int durmap_size;
+ mov_durmap_t* durmap;
+} mov_track_t;
+
+void mov_build_index(mov_track_t* trak){
+ int i,j,s;
+ int last=trak->chunks_size;
+ unsigned int pts=0;
+ printf("MOV track: %d chunks, %d samples\n",trak->chunks_size,trak->samples_size);
+ printf("pts=%d scale=%d time=%5.3f\n",trak->length,trak->timescale,(float)trak->length/(float)trak->timescale);
+ // process chunkmap:
+ i=trak->chunkmap_size;
+ while(i>0){
+ --i;
+ for(j=trak->chunkmap[i].first;j<last;j++){
+ trak->chunks[j].desc=trak->chunkmap[i].sdid;
+ trak->chunks[j].size=trak->chunkmap[i].spc;
+ }
+ last=trak->chunkmap[i].first;
+ }
+
+ // calc pts of chunks:
+ s=0;
+ for(j=0;j<trak->chunks_size;j++){
+ trak->chunks[j].sample=s;
+ s+=trak->chunks[j].size;
+ }
+
+ if(!trak->samples_size){
+ // constant sampesize
+ if(trak->durmap_size==1 || (trak->durmap_size==2 && trak->durmap[1].num==1)){
+ trak->duration=trak->durmap[0].dur;
+ } else printf("*** constant samplesize & variable duration not yet supported! ***\nContact the author if you have such sample file!\n");
+ return;
+ }
+
+ // calc pts:
+ s=0;
+ for(j=0;j<trak->durmap_size;j++){
+ for(i=0;i<trak->durmap[j].num;i++){
+ trak->samples[s].pts=pts;
+ ++s;
+ pts+=trak->durmap[j].dur;
+ }
+ }
+
+ // calc sample offsets
+ s=0;
+ for(j=0;j<trak->chunks_size;j++){
+ off_t pos=trak->chunks[j].pos;
+ for(i=0;i<trak->chunks[j].size;i++){
+ trak->samples[s].pos=pos;
+#if 0
+ printf("Sample %5d: pts=%8d off=0x%08X size=%d\n",s,
+ trak->samples[s].pts,
+ (int)trak->samples[s].pos,
+ trak->samples[s].size);
+#endif
+ pos+=trak->samples[s].size;
+ ++s;
+ }
+ }
+
+}
+
+#define MOV_MAX_TRACKS 256
+
+#define MOV_TRAK_UNKNOWN 0
+#define MOV_TRAK_VIDEO 1
+#define MOV_TRAK_AUDIO 2
+
+typedef struct {
+ off_t moov_start;
+ off_t moov_end;
+ off_t mdat_start;
+ off_t mdat_end;
+ int track_db;
+ mov_track_t* tracks[MOV_MAX_TRACKS];
+} mov_priv_t;
+
+#define MOV_FOURCC(a,b,c,d) ((a<<24)|(b<<16)|(c<<8)|(d))
+
+int mov_check_file(demuxer_t* demuxer){
+ int flags=0;
+ mov_priv_t* priv=malloc(sizeof(mov_priv_t));
+
+ mp_msg(MSGT_DEMUX,MSGL_V,"Checking for MOV\n");
+
+ memset(priv,0,sizeof(mov_priv_t));
+ demuxer->priv=priv;
+
+ while(1){
+ off_t len=stream_read_dword(demuxer->stream);
+ unsigned int id=stream_read_dword(demuxer->stream);
+ if(stream_eof(demuxer->stream)) break; // EOF
+ if(len<8) break; // invalid chunk
+ switch(id){
+ case MOV_FOURCC('m','o','o','v'):
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: Movie header found!\n");
+ priv->moov_start=stream_tell(demuxer->stream);
+ priv->moov_end=priv->moov_start+len-8;
+ flags|=1;
+ break;
+ case MOV_FOURCC('m','d','a','t'):
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: Movie DATA found!\n");
+ priv->mdat_start=stream_tell(demuxer->stream);
+ priv->mdat_end=priv->mdat_start+len-8;
+ flags|=2;
+ break;
+ default:
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: unknown chunk: %.4s %d\n",&id,(int)len);
+ }
+ if(!stream_skip(demuxer->stream,len-8)) break;
+ }
+
+ if(flags==1)
+ mp_msg(MSGT_DEMUX,MSGL_WARN,"MOV: missing data (mdat) chunk! Maybe broken file...\n");
+ else if(flags==2)
+ mp_msg(MSGT_DEMUX,MSGL_WARN,"MOV: missing header (moov/cmov) chunk! Maybe broken file...\n");
+
+return (flags==3);
+}
+
+static void lschunks(demuxer_t* demuxer,int level,off_t endpos,mov_track_t* trak){
+ mov_priv_t* priv=demuxer->priv;
+ while(1){
+ off_t pos;
+ off_t len;
+ unsigned int id;
+ //
+ pos=stream_tell(demuxer->stream);
+// printf("stream_tell==%d\n",pos);
+ if(pos>=endpos) return; // END
+ len=stream_read_dword(demuxer->stream);
+// printf("len==%d\n",len);
+ if(len<8) return; // error
+ len-=8;
+ id=stream_read_dword(demuxer->stream);
+ //
+ mp_msg(MSGT_DEMUX,MSGL_DBG2,"lschunks %.4s %d\n",&id,(int)len);
+ //
+ if(trak){
+ switch(id){
+ case MOV_FOURCC('t','k','h','d'): {
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sTrack header!\n",level,"");
+ // read codec data
+ trak->tkdata_len=len;
+ trak->tkdata=malloc(trak->tkdata_len);
+ stream_read(demuxer->stream,trak->tkdata,trak->tkdata_len);
+ break;
+ }
+ case MOV_FOURCC('m','d','h','d'): {
+ unsigned int tmp;
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sMedia header!\n",level,"");
+#if 0
+ tmp=stream_read_dword(demuxer->stream);
+ printf("dword1: 0x%08X (%d)\n",tmp,tmp);
+ tmp=stream_read_dword(demuxer->stream);
+ printf("dword2: 0x%08X (%d)\n",tmp,tmp);
+ tmp=stream_read_dword(demuxer->stream);
+ printf("dword3: 0x%08X (%d)\n",tmp,tmp);
+ tmp=stream_read_dword(demuxer->stream);
+ printf("dword4: 0x%08X (%d)\n",tmp,tmp);
+ tmp=stream_read_dword(demuxer->stream);
+ printf("dword5: 0x%08X (%d)\n",tmp,tmp);
+ tmp=stream_read_dword(demuxer->stream);
+ printf("dword6: 0x%08X (%d)\n",tmp,tmp);
+#endif
+ stream_skip(demuxer->stream,12);
+ // read timescale
+ trak->timescale=stream_read_dword(demuxer->stream);
+ // read length
+ trak->length=stream_read_dword(demuxer->stream);
+ break;
+ }
+ case MOV_FOURCC('v','m','h','d'): {
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sVideo header!\n",level,"");
+ trak->type=MOV_TRAK_VIDEO;
+ // read video data
+ break;
+ }
+ case MOV_FOURCC('s','m','h','d'): {
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sSound header!\n",level,"");
+ trak->type=MOV_TRAK_AUDIO;
+ // read audio data
+ break;
+ }
+ case MOV_FOURCC('s','t','s','d'): {
+ int i=stream_read_dword(demuxer->stream); // temp!
+ int count=stream_read_dword(demuxer->stream);
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sDescription list! (cnt:%d)\n",level,"",count);
+ for(i=0;i<count;i++){
+ off_t pos=stream_tell(demuxer->stream);
+ off_t len=stream_read_dword(demuxer->stream);
+ unsigned int fourcc=stream_read_dword_le(demuxer->stream);
+ if(len<8) break; // error
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*s desc #%d: %.4s",level,"",i,&fourcc);
+ if(!i){
+ trak->fourcc=fourcc;
+ // read codec data
+ trak->stdata_len=len-8;
+ trak->stdata=malloc(trak->stdata_len);
+ stream_read(demuxer->stream,trak->stdata,trak->stdata_len);
+ if(trak->type==MOV_TRAK_VIDEO && trak->stdata_len>43){
+ mp_msg(MSGT_DEMUX,MSGL_V," '%.*s'",trak->stdata_len-43,trak->stdata+43);
+ }
+ }
+ mp_msg(MSGT_DEMUX,MSGL_V,"\n");
+ if(fourcc!=trak->fourcc && i)
+ mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_MOVvariableFourCC);
+ if(!stream_seek(demuxer->stream,pos+len)) break;
+ }
+ break;
+ }
+ case MOV_FOURCC('s','t','t','s'): {
+ int temp=stream_read_dword(demuxer->stream);
+ int len=stream_read_dword(demuxer->stream);
+ int i;
+ int x=0;
+ unsigned int pts=0;
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sSample duration table! (%d blocks)\n",level,"",len);
+ trak->durmap=malloc(sizeof(mov_durmap_t)*len);
+ memset(trak->durmap,0,sizeof(mov_durmap_t)*len);
+ trak->durmap_size=len;
+ for(i=0;i<len;i++){
+ trak->durmap[i].num=stream_read_dword(demuxer->stream);
+ trak->durmap[i].dur=stream_read_dword(demuxer->stream);
+ pts+=trak->durmap[i].num*trak->durmap[i].dur;
+ }
+ if(trak->length!=pts) printf("Warning! pts=%d length=%d\n",pts,trak->length);
+ break;
+ }
+ case MOV_FOURCC('s','t','s','c'): {
+ int temp=stream_read_dword(demuxer->stream);
+ int len=stream_read_dword(demuxer->stream);
+ int i;
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sSample->Chunk mapping table! (%d blocks)\n",level,"",len);
+ // read data:
+ trak->chunkmap_size=len;
+ trak->chunkmap=malloc(sizeof(mov_chunkmap_t)*len);
+ for(i=0;i<len;i++){
+ trak->chunkmap[i].first=stream_read_dword(demuxer->stream)-1;
+ trak->chunkmap[i].spc=stream_read_dword(demuxer->stream);
+ trak->chunkmap[i].sdid=stream_read_dword(demuxer->stream);
+ }
+ break;
+ }
+ case MOV_FOURCC('s','t','s','z'): {
+ int temp=stream_read_dword(demuxer->stream);
+ int ss=stream_read_dword(demuxer->stream);
+ int len=stream_read_dword(demuxer->stream);
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sSample size table! len=%d ss=%d\n",level,"",len,ss);
+ trak->samplesize=ss;
+ if(!ss){
+ // variable samplesize
+ int i;
+ trak->samples=realloc(trak->samples,sizeof(mov_sample_t)*len);
+ trak->samples_size=len;
+ for(i=0;i<len;i++)
+ trak->samples[i].size=stream_read_dword(demuxer->stream);
+ }
+ break;
+ }
+ case MOV_FOURCC('s','t','c','o'): {
+ int temp=stream_read_dword(demuxer->stream);
+ int len=stream_read_dword(demuxer->stream);
+ int i;
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sChunk offset table! (%d chunks)\n",level,"",len);
+ // extend array if needed:
+ if(len>trak->chunks_size){
+ trak->chunks=realloc(trak->chunks,sizeof(mov_chunk_t)*len);
+ trak->chunks_size=len;
+ }
+ // read elements:
+ for(i=0;i<len;i++) trak->chunks[i].pos=stream_read_dword(demuxer->stream);
+ break;
+ }
+ case MOV_FOURCC('m','d','i','a'): {
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sMedia stream!\n",level,"");
+ lschunks(demuxer,level+1,pos+len,trak);
+ break;
+ }
+ case MOV_FOURCC('m','i','n','f'): {
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sMedia info!\n",level,"");
+ lschunks(demuxer,level+1,pos+len,trak);
+ break;
+ }
+ case MOV_FOURCC('s','t','b','l'): {
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: %*sSample info!\n",level,"");
+ lschunks(demuxer,level+1,pos+len,trak);
+ break;
+ }
+ }//switch(id)
+ } else
+ if(id==MOV_FOURCC('t','r','a','k')){
+// if(trak) printf("MOV: Warning! trak in trak?\n");
+ if(priv->track_db>=MOV_MAX_TRACKS){
+ mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_MOVtooManyTrk);
+ return;
+ }
+ trak=malloc(sizeof(mov_track_t));
+ memset(trak,0,sizeof(mov_track_t));
+ mp_msg(MSGT_DEMUX,MSGL_V,"MOV: Track #%d:\n",priv->track_db);
+ trak->id=priv->track_db;
+ priv->tracks[priv->track_db]=trak;
+ lschunks(demuxer,level+1,pos+len,trak);
+ mov_build_index(trak);
+ switch(trak->type){
+ case MOV_TRAK_AUDIO: {
+ sh_audio_t* sh=new_sh_audio(demuxer,priv->track_db);
+ sh->format=trak->fourcc;
+ printf("!!! audio bits: %d chans: %d\n",trak->stdata[19],trak->stdata[17]);
+ printf("Fourcc: %.4s\n",&trak->fourcc);
+ // Emulate WAVEFORMATEX struct:
+ sh->wf=malloc(sizeof(WAVEFORMATEX));
+ memset(sh->wf,0,sizeof(WAVEFORMATEX));
+ sh->wf->nChannels=trak->stdata[17];
+ sh->wf->wBitsPerSample=trak->stdata[19];
+ sh->wf->nSamplesPerSec=trak->timescale;
+ sh->wf->nAvgBytesPerSec=sh->wf->nChannels*((sh->wf->wBitsPerSample+7)/8)*sh->wf->nSamplesPerSec;
+ // Selection:
+ if(demuxer->audio->id==-1 || demuxer->audio->id==priv->track_db){
+ // (auto)selected audio track:
+ demuxer->audio->id=priv->track_db;
+ demuxer->audio->sh=sh; sh->ds=demuxer->audio;
+ }
+ break;
+ }
+ case MOV_TRAK_VIDEO: {
+ sh_video_t* sh=new_sh_video(demuxer,priv->track_db);
+ sh->format=trak->fourcc;
+ sh->fps=trak->timescale;
+ sh->frametime=1.0f/sh->fps;
+ sh->disp_w=trak->tkdata[77]|(trak->tkdata[76]<<8);
+ sh->disp_h=trak->tkdata[81]|(trak->tkdata[80]<<8);
+
+ // emulate BITMAPINFOHEADER:
+ sh->bih=malloc(sizeof(BITMAPINFOHEADER));
+ memset(sh->bih,0,sizeof(BITMAPINFOHEADER));
+ sh->bih->biSize=40;
+ sh->bih->biWidth=sh->disp_w;
+ sh->bih->biHeight=sh->disp_h;
+ sh->bih->biPlanes=0;
+ sh->bih->biBitCount=16;
+ sh->bih->biCompression=trak->fourcc;
+ sh->bih->biSizeImage=sh->bih->biWidth*sh->bih->biHeight;
+
+ printf("Image size: %d x %d\n",sh->disp_w,sh->disp_h);
+ printf("Fourcc: %.4s Codec: '%.*s'\n",&trak->fourcc,trak->stdata_len-43,trak->stdata+43);
+
+ if(demuxer->video->id==-1 || demuxer->video->id==priv->track_db){
+ // (auto)selected video track:
+ demuxer->video->id=priv->track_db;
+ demuxer->video->sh=sh; sh->ds=demuxer->video;
+ }
+ break;
+ }
+ }
+ printf("--------------\n");
+ priv->track_db++;
+ trak=NULL;
+ } else
+#ifndef HAVE_ZLIB
+ if(id==MOV_FOURCC('c','m','o','v')){
+ mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_MOVcomprhdr);
+ return;
+ }
+#else
+ if(id==MOV_FOURCC('c','m','o','v')){
+// mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_MOVcomprhdr);
+ lschunks(demuxer,level+1,pos+len,NULL);
+ } else
+ if(id==MOV_FOURCC('d','c','o','m')){
+// int temp=stream_read_dword(demuxer->stream);
+ unsigned int len=stream_read_dword(demuxer->stream);
+ printf("Compressed header uses %.4s algo!\n",&len);
+ } else
+ if(id==MOV_FOURCC('c','m','v','d')){
+// int temp=stream_read_dword(demuxer->stream);
+ unsigned int moov_sz=stream_read_dword(demuxer->stream);
+ unsigned int cmov_sz=len-4;
+ unsigned char* cmov_buf=malloc(cmov_sz);
+ unsigned char* moov_buf=malloc(moov_sz+16);
+ int zret;
+ z_stream zstrm;
+ stream_t* backup;
+
+ printf("Compressed header size: %d / %d\n",cmov_sz,moov_sz);
+
+ stream_read(demuxer->stream,cmov_buf,cmov_sz);
+
+ zstrm.zalloc = (alloc_func)0;
+ zstrm.zfree = (free_func)0;
+ zstrm.opaque = (voidpf)0;
+ zstrm.next_in = cmov_buf;
+ zstrm.avail_in = cmov_sz;
+ zstrm.next_out = moov_buf;
+ zstrm.avail_out = moov_sz;
+
+ zret = inflateInit(&zstrm);
+ if (zret != Z_OK)
+ { fprintf(stderr,"QT cmov: inflateInit err %d\n",zret);
+ return;
+ }
+ zret = inflate(&zstrm, Z_NO_FLUSH);
+ if ((zret != Z_OK) && (zret != Z_STREAM_END))
+ { fprintf(stderr,"QT cmov inflate: ERR %d\n",zret);
+ return;
+ }
+#if 0
+ else {
+ FILE *DecOut;
+ DecOut = fopen("Out.bin", "w");
+ fwrite(moov_buf, 1, moov_sz, DecOut);
+ fclose(DecOut);
+ }
+#endif
+ if(moov_sz != zstrm.total_out) printf("Warning! moov size differs cmov: %d zlib: %d\n",moov_sz,zstrm.total_out);
+ zret = inflateEnd(&zstrm);
+
+ backup=demuxer->stream;
+ demuxer->stream=new_memory_stream(moov_buf,moov_sz);
+ stream_skip(demuxer->stream,8);
+ lschunks(demuxer,level+1,moov_sz,NULL); // parse uncompr. 'moov'
+ //free_stream(demuxer->stream);
+ demuxer->stream=backup;
+
+ }
+#endif
+
+ pos+=len+8;
+ if(pos>=endpos) break;
+ if(!stream_seek(demuxer->stream,pos)) break;
+ }
+}
+
+int mov_read_header(demuxer_t* demuxer){
+ mov_priv_t* priv=demuxer->priv;
+
+ printf("mov_read_header!\n");
+
+ // Parse header:
+ stream_reset(demuxer->stream);
+ if(!stream_seek(demuxer->stream,priv->moov_start)) return 0; // ???
+ lschunks(demuxer, 0, priv->moov_end, NULL);
+
+#if 1
+ return 1;
+#else
+ mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_MOVnotyetsupp);
+ return 0;
+#endif
+}
+
+// return value:
+// 0 = EOF or no stream found
+// 1 = successfully read a packet
+int demux_mov_fill_buffer(demuxer_t *demuxer,demux_stream_t* ds){
+ mov_priv_t* priv=demuxer->priv;
+ mov_track_t* trak=NULL;
+ float pts;
+
+ if(ds->id<0 || ds->id>=priv->track_db) return 0;
+ trak=priv->tracks[ds->id];
+
+if(trak->samplesize){
+ // read chunk:
+ if(trak->pos>=trak->chunks_size) return 0; // EOF
+ stream_seek(demuxer->stream,trak->chunks[trak->pos].pos);
+ pts=(float)(trak->chunks[trak->pos].sample*trak->duration)/(float)trak->timescale;
+ ds_read_packet(ds,demuxer->stream,trak->chunks[trak->pos].size*trak->samplesize,pts,trak->chunks[trak->pos].pos,0);
+} else {
+ // read sample:
+ if(trak->pos>=trak->samples_size) return 0; // EOF
+ stream_seek(demuxer->stream,trak->samples[trak->pos].pos);
+ pts=(float)trak->samples[trak->pos].pts/(float)trak->timescale;
+ ds_read_packet(ds,demuxer->stream,trak->samples[trak->pos].size,pts,trak->samples[trak->pos].pos,0);
+}
+ ++trak->pos;
+
+ return 1;
+
+}
+
+static float mov_seek_track(mov_track_t* trak,float pts,int flags){
+
+// printf("MOV track seek called %5.3f \n",pts);
+ if(flags&2) pts*=trak->length; else pts*=(float)trak->timescale;
+
+if(trak->samplesize){
+ int sample=pts/trak->duration;
+// printf("MOV track seek - chunk: %d (pts: %5.3f dur=%d) \n",sample,pts,trak->duration);
+ if(!(flags&1)) sample+=trak->chunks[trak->pos].sample; // relative
+ trak->pos=0;
+ while(trak->pos<trak->chunks_size && trak->chunks[trak->pos].sample<sample) ++trak->pos;
+ pts=(float)(trak->chunks[trak->pos].sample*trak->duration)/(float)trak->timescale;
+} else {
+ unsigned int ipts=pts;
+// printf("MOV track seek - sample: %d \n",ipts);
+ if(!(flags&1)) ipts+=trak->samples[trak->pos].pts;
+ trak->pos=0;
+ while(trak->pos<trak->samples_size && trak->samples[trak->pos].pts<ipts) ++trak->pos;
+ pts=(float)trak->samples[trak->pos].pts/(float)trak->timescale;
+}
+
+// printf("MOV track seek done: %5.3f \n",pts);
+
+return pts;
+}
+
+void demux_seek_mov(demuxer_t *demuxer,float pts,int flags){
+ mov_priv_t* priv=demuxer->priv;
+ demux_stream_t* ds;
+
+// printf("MOV seek called %5.3f flag=%d \n",pts,flags);
+
+ ds=demuxer->video;
+ if(ds && ds->id>=0 && ds->id<priv->track_db){
+ mov_track_t* trak=priv->tracks[ds->id];
+ //if(flags&2) pts*=(float)trak->length/(float)trak->timescale;
+ //if(!(flags&1)) pts+=ds->pts;
+ pts=ds->pts=mov_seek_track(trak,pts,flags);
+ flags=1; // absolute seconds
+ }
+
+ ds=demuxer->audio;
+ if(ds && ds->id>=0 && ds->id<priv->track_db){
+ mov_track_t* trak=priv->tracks[ds->id];
+ //if(flags&2) pts*=(float)trak->length/(float)trak->timescale;
+ //if(!(flags&1)) pts+=ds->pts;
+ ds->pts=mov_seek_track(trak,pts,flags);
+ }
+
+}
+
diff --git a/libmpdemux/demux_mpg.c b/libmpdemux/demux_mpg.c
new file mode 100644
index 0000000000..dc4cc7f438
--- /dev/null
+++ b/libmpdemux/demux_mpg.c
@@ -0,0 +1,403 @@
+// MPG/VOB file parser for DEMUXER v2.5 by A'rpi/ESP-team
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "config.h"
+#include "dvdauth.h"
+#include "stream.h"
+#include "demuxer.h"
+#include "parse_es.h"
+
+//#define MAX_PS_PACKETSIZE 2048
+#define MAX_PS_PACKETSIZE (224*1024)
+
+static int mpeg_pts_error=0;
+
+static unsigned int read_mpeg_timestamp(stream_t *s,int c){
+ int d,e;
+ unsigned int pts;
+ d=stream_read_word(s);
+ e=stream_read_word(s);
+ if( ((c&1)!=1) || ((d&1)!=1) || ((e&1)!=1) ){
+ ++mpeg_pts_error;
+ return 0; // invalid pts
+ }
+ pts=(((c>>1)&7)<<30)|((d>>1)<<15)|(e>>1);
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3,"{%d}",pts);
+ return pts;
+}
+
+//static unsigned int packet_start_pos=0;
+
+//extern void *new_sh_audio(demuxer_t *demux,int id);
+//extern void *new_sh_video(demuxer_t *demux,int id);
+#include "wine/mmreg.h"
+#include "wine/avifmt.h"
+#include "wine/vfw.h"
+
+#include "codec-cfg.h"
+#include "stheader.h"
+
+static int demux_mpg_read_packet(demuxer_t *demux,int id){
+ int d;
+ int len;
+#ifdef HAVE_LIBCSS
+ int css=0;
+#endif
+ unsigned char c=0;
+ unsigned int pts=0;
+ unsigned int dts=0;
+ demux_stream_t *ds=NULL;
+
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3,"demux_read_packet: %X\n",id);
+
+// if(id==0x1F0){
+// demux->synced=0; // force resync after 0x1F0
+// return -1;
+//}
+
+// if(id==0x1BA) packet_start_pos=stream_tell(demux->stream);
+ if(id<0x1BC || id>=0x1F0) return -1;
+ if(id==0x1BE) return -1; // padding stream
+ if(id==0x1BF) return -1; // private2
+
+ len=stream_read_word(demux->stream);
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3,"PACKET len=%d",len);
+// if(len==62480){ demux->synced=0;return -1;} /* :) */
+ if(len==0 || len>MAX_PS_PACKETSIZE){
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"Invalid PS packet len: %d\n",len);
+ return -2; // invalid packet !!!!!!
+ }
+
+ mpeg_pts_error=0;
+
+ while(len>0){ // Skip stuFFing bytes
+ c=stream_read_char(demux->stream);--len;
+ if(c!=0xFF)break;
+ }
+ if((c>>6)==1){ // Read (skip) STD scale & size value
+// printf(" STD_scale=%d",(c>>5)&1);
+ d=((c&0x1F)<<8)|stream_read_char(demux->stream);
+ len-=2;
+// printf(" STD_size=%d",d);
+ c=stream_read_char(demux->stream);
+ }
+ // Read System-1 stream timestamps:
+ if((c>>4)==2){
+ pts=read_mpeg_timestamp(demux->stream,c);
+ len-=4;
+ } else
+ if((c>>4)==3){
+ pts=read_mpeg_timestamp(demux->stream,c);
+ c=stream_read_char(demux->stream);
+ if((c>>4)!=1) pts=0; //printf("{ERROR4}");
+ dts=read_mpeg_timestamp(demux->stream,c);
+ len-=4+1+4;
+ } else
+ if((c>>6)==2){
+ int pts_flags;
+ int hdrlen;
+ // System-2 (.VOB) stream:
+ if((c>>4)&3) {
+#ifdef HAVE_LIBCSS
+ css=1;
+#else
+ mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_EncryptedVOB);
+#endif
+ }
+ c=stream_read_char(demux->stream); pts_flags=c>>6;
+ c=stream_read_char(demux->stream); hdrlen=c;
+ len-=2;
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3," hdrlen=%d (len=%d)",hdrlen,len);
+ if(hdrlen>len){ mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: invalid header length \n"); return -1;}
+ if(pts_flags==2){
+ c=stream_read_char(demux->stream);
+ pts=read_mpeg_timestamp(demux->stream,c);
+ len-=5;hdrlen-=5;
+ } else
+ if(pts_flags==3){
+ c=stream_read_char(demux->stream);
+ pts=read_mpeg_timestamp(demux->stream,c);
+ c=stream_read_char(demux->stream);
+ dts=read_mpeg_timestamp(demux->stream,c);
+ len-=10;hdrlen-=10;
+ }
+ len-=hdrlen;
+ if(hdrlen>0) stream_skip(demux->stream,hdrlen); // skip header bytes
+
+ //============== DVD Audio sub-stream ======================
+ if(id==0x1BD){
+ int aid=stream_read_char(demux->stream);--len;
+ if(len<3) return -1; // invalid audio packet
+
+ // AID:
+ // 0x20..0x3F subtitle
+ // 0x80..0x9F AC3 audio
+ // 0xA0..0xBF PCM audio
+
+ if((aid & 0xE0) == 0x20){
+ // subtitle:
+ aid&=0x1F;
+
+ if(!demux->s_streams[aid]){
+ mp_msg(MSGT_DEMUX,MSGL_V,"==> Found subtitle: %d\n",aid);
+ demux->s_streams[aid]=1;
+ }
+
+ if(demux->sub->id==aid){
+ ds=demux->sub;
+ }
+
+ } else if((aid & 0xC0) == 0x80) {
+
+// aid=128+(aid&0x7F);
+ // aid=0x80..0xBF
+
+ if(!demux->a_streams[aid]) new_sh_audio(demux,aid);
+ if(demux->audio->id==-1) demux->audio->id=aid;
+
+ if(demux->audio->id==aid){
+// int type;
+ ds=demux->audio;
+ if(!ds->sh) ds->sh=demux->a_streams[aid];
+ // READ Packet: Skip additional audio header data:
+ c=stream_read_char(demux->stream);//type=c;
+ c=stream_read_char(demux->stream);//type|=c<<8;
+ c=stream_read_char(demux->stream);//type|=c<<16;
+// printf("[%06X]",type);
+ len-=3;
+ if((aid&0xE0)==0xA0 && len>=2){
+ // read PCM header
+ int head;
+ head=stream_read_char(demux->stream); head=c<<8;
+ c=stream_read_char(demux->stream); head|=c; len-=2;
+ while(len>0 && head!=0x180){
+ head=c<<8;
+ c=stream_read_char(demux->stream);
+ head|=c;--len;
+ }
+ if(!len) mp_msg(MSGT_DEMUX,MSGL_V,"End of packet while searching for PCM header\n");
+ }
+ } // if(demux->audio->id==aid)
+
+ } else mp_msg(MSGT_DEMUX,MSGL_V,"Unknown 0x1BD substream: 0x%02X \n",aid);
+
+ } //if(id==0x1BD)
+
+ } else {
+ if(c!=0x0f){
+ mp_msg(MSGT_DEMUX,MSGL_V," {ERROR5,c=%d} \n",c);
+ return -1; // invalid packet !!!!!!
+ }
+ }
+ if(mpeg_pts_error) mp_msg(MSGT_DEMUX,MSGL_V," {PTS_err:%d} \n",mpeg_pts_error);
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3," => len=%d\n",len);
+
+// if(len<=0 || len>MAX_PS_PACKETSIZE) return -1; // Invalid packet size
+ if(len<=0 || len>MAX_PS_PACKETSIZE){
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"Invalid PS data len: %d\n",len);
+ return -1; // invalid packet !!!!!!
+ }
+
+ if(id>=0x1C0 && id<=0x1DF){
+ // mpeg audio
+ int aid=id-0x1C0;
+ if(!demux->a_streams[aid]) new_sh_audio(demux,aid);
+ if(demux->audio->id==-1) demux->audio->id=aid;
+ if(demux->audio->id==aid){
+ ds=demux->audio;
+ if(!ds->sh) ds->sh=demux->a_streams[aid];
+ }
+ } else
+ if(id>=0x1E0 && id<=0x1EF){
+ // mpeg video
+ int aid=id-0x1E0;
+ if(!demux->v_streams[aid]) new_sh_video(demux,aid);
+ if(demux->video->id==-1) demux->video->id=aid;
+ if(demux->video->id==aid){
+ ds=demux->video;
+ if(!ds->sh) ds->sh=demux->v_streams[aid];
+ }
+ }
+
+ if(ds){
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_MPG: Read %d data bytes from packet %04X\n",len,id);
+// printf("packet start = 0x%X \n",stream_tell(demux->stream)-packet_start_pos);
+#ifdef HAVE_LIBCSS
+ if (css) {
+ if (descrambling) CSSDescramble(demux->stream->buffer,key_title); else
+ mp_msg(MSGT_DEMUX,MSGL_WARN,MSGTR_EncryptedVOBauth);
+ }
+#endif
+ ds_read_packet(ds,demux->stream,len,pts/90000.0f,demux->filepos,0);
+// if(ds==demux->sub) parse_dvdsub(ds->last->buffer,ds->last->len);
+ return 1;
+ }
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_MPG: Skipping %d data bytes from packet %04X\n",len,id);
+ if(len<=2356) stream_skip(demux->stream,len);
+ return 0;
+}
+
+int num_elementary_packets100=0;
+int num_elementary_packets101=0;
+int num_elementary_packets1B6=0;
+int num_elementary_packetsPES=0;
+
+int demux_mpg_es_fill_buffer(demuxer_t *demux){
+ // Elementary video stream
+ if(demux->stream->eof) return 0;
+ demux->filepos=stream_tell(demux->stream);
+ ds_read_packet(demux->video,demux->stream,STREAM_BUFFER_SIZE,0,demux->filepos,0);
+ return 1;
+}
+
+int demux_mpg_fill_buffer(demuxer_t *demux){
+unsigned int head=0;
+int skipped=0;
+int max_packs=128;
+int ret=0;
+
+// System stream
+do{
+ demux->filepos=stream_tell(demux->stream);
+ head=stream_read_dword(demux->stream);
+ if((head&0xFFFFFF00)!=0x100){
+ // sync...
+ demux->filepos-=skipped;
+ while(1){
+ int c=stream_read_char(demux->stream);
+ if(c<0) break; //EOF
+ head<<=8;
+ if(head!=0x100){
+ head|=c;
+ ++skipped; //++demux->filepos;
+ continue;
+ }
+ head|=c;
+ break;
+ }
+ demux->filepos+=skipped;
+ }
+ if(stream_eof(demux->stream)) break;
+ // sure: head=0x000001XX
+ mp_dbg(MSGT_DEMUX,MSGL_DBG4,"*** head=0x%X\n",head);
+ if(demux->synced==0){
+ if(head==0x1BA) demux->synced=1;
+#if 0
+ else if(head>=0x1C0 && head<=0x1EF){
+ demux->synced=2;
+ mp_msg(MSGT_DEMUX,MSGL_V,"Mpeg PES stream synced at 0x%X (%d)!\n",demux->filepos,demux->filepos);
+ num_elementary_packets100=0; // requires for re-sync!
+ num_elementary_packets101=0; // requires for re-sync!
+ }
+#endif
+ } else
+ if(demux->synced==1){
+ if(head==0x1BB || head==0x1BD || (head>=0x1C0 && head<=0x1EF)){
+ demux->synced=2;
+ mp_msg(MSGT_DEMUX,MSGL_V,"system stream synced at 0x%X (%d)!\n",demux->filepos,demux->filepos);
+ num_elementary_packets100=0; // requires for re-sync!
+ num_elementary_packets101=0; // requires for re-sync!
+ } else demux->synced=0;
+ } // else
+ if(demux->synced==2){
+ ret=demux_mpg_read_packet(demux,head);
+ if(!ret)
+ if(--max_packs==0){
+ demux->stream->eof=1;
+ mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_DoesntContainSelectedStream);
+ return 0;
+ }
+ } else {
+ if(head>=0x100 && head<0x1B0){
+ if(head==0x100) ++num_elementary_packets100; else
+ if(head==0x101) ++num_elementary_packets101;
+ mp_msg(MSGT_DEMUX,MSGL_DBG3,"Opps... elementary video packet found: %03X\n",head);
+ } else
+ if(head>=0x1C0 && head<0x1F0){
+ ++num_elementary_packetsPES;
+ mp_msg(MSGT_DEMUX,MSGL_DBG3,"Opps... PES packet found: %03X\n",head);
+ } else
+ if(head==0x1B6) ++num_elementary_packets1B6;
+#if 1
+ if( ( (num_elementary_packets100>50 && num_elementary_packets101>50) ||
+ (num_elementary_packetsPES>50) ) && skipped>4000000){
+ mp_msg(MSGT_DEMUX,MSGL_V,"sync_mpeg_ps: seems to be ES/PES stream...\n");
+ demux->stream->eof=1;
+ break;
+ }
+#endif
+ }
+} while(ret!=1);
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"demux: %d bad bytes skipped\n",skipped);
+ if(demux->stream->eof){
+ mp_msg(MSGT_DEMUX,MSGL_V,"MPEG Stream reached EOF\n");
+ return 0;
+ }
+ return 1;
+}
+
+//extern off_t seek_to_byte;
+
+void demux_seek_mpg(demuxer_t *demuxer,float rel_seek_secs,int flags){
+ demux_stream_t *d_audio=demuxer->audio;
+ demux_stream_t *d_video=demuxer->video;
+ sh_audio_t *sh_audio=d_audio->sh;
+ sh_video_t *sh_video=d_video->sh;
+
+ //================= seek in MPEG ==========================
+ off_t newpos=(flags&1)?demuxer->movi_start:demuxer->filepos;
+
+ if(flags&2){
+ // float seek 0..1
+ newpos+=(demuxer->movi_end-demuxer->movi_start)*rel_seek_secs;
+ } else {
+ // time seek (secs)
+ if(!sh_video->i_bps) // unspecified or VBR
+ newpos+=2324*75*rel_seek_secs; // 174.3 kbyte/sec
+ else
+ newpos+=sh_video->i_bps*rel_seek_secs;
+ }
+
+ if(newpos<demuxer->movi_start) newpos=demuxer->movi_start;
+
+#ifdef _LARGEFILE_SOURCE
+ newpos&=~((long long)STREAM_BUFFER_SIZE-1); /* sector boundary */
+#else
+ newpos&=~(STREAM_BUFFER_SIZE-1); /* sector boundary */
+#endif
+ stream_seek(demuxer->stream,newpos);
+
+ // re-sync video:
+ videobuf_code_len=0; // reset ES stream buffer
+
+ ds_fill_buffer(d_video);
+ if(sh_audio){
+ ds_fill_buffer(d_audio);
+ resync_audio_stream(sh_audio);
+ }
+
+ while(1){
+ int i;
+ if(sh_audio && !d_audio->eof && d_video->pts && d_audio->pts){
+ float a_pts=d_audio->pts;
+ a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
+ if(d_video->pts>a_pts){
+ skip_audio_frame(sh_audio); // sync audio
+ continue;
+ }
+ }
+ i=sync_video_packet(d_video);
+ if(i==0x1B3 || i==0x1B8) break; // found it!
+ if(!i || !skip_video_packet(d_video)) break; // EOF?
+ }
+
+
+}
+
diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c
new file mode 100644
index 0000000000..f573ef7860
--- /dev/null
+++ b/libmpdemux/demuxer.c
@@ -0,0 +1,580 @@
+//=================== DEMUXER v2.5 =========================
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "stream.h"
+#include "demuxer.h"
+
+#include "wine/mmreg.h"
+#include "wine/avifmt.h"
+#include "wine/vfw.h"
+
+#include "codec-cfg.h"
+#include "stheader.h"
+
+void free_demuxer_stream(demux_stream_t *ds){
+ ds_free_packs(ds);
+ free(ds);
+}
+
+demux_stream_t* new_demuxer_stream(struct demuxer_st *demuxer,int id){
+ demux_stream_t* ds=malloc(sizeof(demux_stream_t));
+ ds->buffer_pos=ds->buffer_size=0;
+ ds->buffer=NULL;
+ ds->pts=0;
+ ds->pts_bytes=0;
+ ds->eof=0;
+ ds->pos=0;
+ ds->dpos=0;
+ ds->pack_no=0;
+//---------------
+ ds->packs=0;
+ ds->bytes=0;
+ ds->first=ds->last=NULL;
+ ds->id=id;
+ ds->demuxer=demuxer;
+//----------------
+ ds->asf_seq=-1;
+ ds->asf_packet=NULL;
+//----------------
+ ds->sh=NULL;
+ return ds;
+}
+
+demuxer_t* new_demuxer(stream_t *stream,int type,int a_id,int v_id,int s_id){
+ demuxer_t *d=malloc(sizeof(demuxer_t));
+ memset(d,0,sizeof(demuxer_t));
+ d->stream=stream;
+ d->movi_start=stream->start_pos;
+ d->movi_end=stream->end_pos;
+ d->seekable=1;
+ d->synced=0;
+ d->filepos=0;
+ d->audio=new_demuxer_stream(d,a_id);
+ d->video=new_demuxer_stream(d,v_id);
+ d->sub=new_demuxer_stream(d,s_id);
+ d->type=type;
+ stream_reset(stream);
+ stream_seek(stream,stream->start_pos);
+ return d;
+}
+
+sh_audio_t* new_sh_audio(demuxer_t *demuxer,int id){
+ if(demuxer->a_streams[id]){
+ mp_msg(MSGT_DEMUXER,MSGL_WARN,MSGTR_AudioStreamRedefined,id);
+ } else {
+ mp_msg(MSGT_DEMUXER,MSGL_V,"==> Found audio stream: %d\n",id);
+ demuxer->a_streams[id]=malloc(sizeof(sh_audio_t));
+ memset(demuxer->a_streams[id],0,sizeof(sh_audio_t));
+ }
+ return demuxer->a_streams[id];
+}
+
+void free_sh_audio(sh_audio_t* sh){
+ if(sh->a_in_buffer) free(sh->a_in_buffer);
+ if(sh->a_buffer) free(sh->a_buffer);
+ if(sh->wf) free(sh->wf);
+ free(sh);
+}
+
+sh_video_t* new_sh_video(demuxer_t *demuxer,int id){
+ if(demuxer->v_streams[id]){
+ mp_msg(MSGT_DEMUXER,MSGL_WARN,MSGTR_VideoStreamRedefined,id);
+ } else {
+ mp_msg(MSGT_DEMUXER,MSGL_V,"==> Found video stream: %d\n",id);
+ demuxer->v_streams[id]=malloc(sizeof(sh_video_t));
+ memset(demuxer->v_streams[id],0,sizeof(sh_video_t));
+ }
+ return demuxer->v_streams[id];
+}
+
+void free_sh_video(sh_video_t* sh){
+ if(sh->our_out_buffer) free(sh->our_out_buffer);
+ if(sh->bih) free(sh->bih);
+ free(sh);
+}
+
+void free_demuxer(demuxer_t *demuxer){
+ int i;
+ // free streams:
+ for(i=0;i<256;i++){
+ if(demuxer->a_streams[i]) free_sh_audio(demuxer->a_streams[i]);
+ if(demuxer->v_streams[i]) free_sh_video(demuxer->v_streams[i]);
+ }
+ //if(sh_audio) free_sh_audio(sh_audio);
+ //if(sh_video) free_sh_video(sh_video);
+ // free demuxers:
+ free_demuxer_stream(demuxer->audio);
+ free_demuxer_stream(demuxer->video);
+ free(demuxer);
+}
+
+
+void ds_add_packet(demux_stream_t *ds,demux_packet_t* dp){
+// demux_packet_t* dp=new_demux_packet(len);
+// stream_read(stream,dp->buffer,len);
+// dp->pts=pts; //(float)pts/90000.0f;
+// dp->pos=pos;
+ // append packet to DS stream:
+ ++ds->packs;
+ ds->bytes+=dp->len;
+ if(ds->last){
+ // next packet in stream
+ ds->last->next=dp;
+ ds->last=dp;
+ } else {
+ // first packet in stream
+ ds->first=ds->last=dp;
+ }
+ mp_dbg(MSGT_DEMUXER,MSGL_DBG2,"DEMUX: Append packet to %s, len=%d pts=%5.3f pos=%u [packs: A=%d V=%d]\n",
+ (ds==ds->demuxer->audio)?"d_audio":"d_video",
+ dp->len,dp->pts,(unsigned int)dp->pos,ds->demuxer->audio->packs,ds->demuxer->video->packs);
+}
+
+void ds_read_packet(demux_stream_t *ds,stream_t *stream,int len,float pts,off_t pos,int flags){
+ demux_packet_t* dp=new_demux_packet(len);
+ stream_read(stream,dp->buffer,len);
+ dp->pts=pts; //(float)pts/90000.0f;
+ dp->pos=pos;
+ dp->flags=flags;
+ // append packet to DS stream:
+ ds_add_packet(ds,dp);
+}
+
+// return value:
+// 0 = EOF or no stream found or invalid type
+// 1 = successfully read a packet
+int demux_mpg_es_fill_buffer(demuxer_t *demux);
+int demux_mpg_fill_buffer(demuxer_t *demux);
+int demux_avi_fill_buffer(demuxer_t *demux);
+int demux_avi_fill_buffer_ni(demuxer_t *demux,demux_stream_t *ds);
+int demux_avi_fill_buffer_nini(demuxer_t *demux,demux_stream_t *ds);
+int demux_asf_fill_buffer(demuxer_t *demux);
+int demux_mov_fill_buffer(demuxer_t *demux,demux_stream_t* ds);
+
+int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){
+ // Note: parameter 'ds' can be NULL!
+// printf("demux->type=%d\n",demux->type);
+ switch(demux->type){
+ case DEMUXER_TYPE_MPEG_ES: return demux_mpg_es_fill_buffer(demux);
+ case DEMUXER_TYPE_MPEG_PS: return demux_mpg_fill_buffer(demux);
+ case DEMUXER_TYPE_AVI: return demux_avi_fill_buffer(demux);
+ case DEMUXER_TYPE_AVI_NI: return demux_avi_fill_buffer_ni(demux,ds);
+ case DEMUXER_TYPE_AVI_NINI: return demux_avi_fill_buffer_nini(demux,ds);
+ case DEMUXER_TYPE_ASF: return demux_asf_fill_buffer(demux);
+ case DEMUXER_TYPE_MOV: return demux_mov_fill_buffer(demux,ds);
+ }
+ return 0;
+}
+
+// return value:
+// 0 = EOF
+// 1 = succesfull
+int ds_fill_buffer(demux_stream_t *ds){
+ demuxer_t *demux=ds->demuxer;
+ if(ds->buffer) free(ds->buffer);
+ if(verbose>2){
+ if(ds==demux->audio) mp_dbg(MSGT_DEMUXER,MSGL_DBG3,"ds_fill_buffer(d_audio) called\n");else
+ if(ds==demux->video) mp_dbg(MSGT_DEMUXER,MSGL_DBG3,"ds_fill_buffer(d_video) called\n");else
+ mp_dbg(MSGT_DEMUXER,MSGL_DBG3,"ds_fill_buffer(unknown 0x%X) called\n",(unsigned int)ds);
+ }
+ while(1){
+ if(ds->packs){
+ demux_packet_t *p=ds->first;
+ // copy useful data:
+ ds->buffer=p->buffer;
+ ds->buffer_pos=0;
+ ds->buffer_size=p->len;
+ ds->pos=p->pos;
+ ds->dpos+=p->len; // !!!
+ ++ds->pack_no;
+ if(p->pts){
+ ds->pts=p->pts;
+ ds->pts_bytes=0;
+ }
+ ds->pts_bytes+=p->len; // !!!
+ ds->flags=p->flags;
+ // free packet:
+ ds->bytes-=p->len;
+ ds->first=p->next;
+ if(!ds->first) ds->last=NULL;
+ free(p);
+ --ds->packs;
+ return 1; //ds->buffer_size;
+ }
+ if(demux->audio->packs>=MAX_PACKS || demux->audio->bytes>=MAX_PACK_BYTES){
+ mp_msg(MSGT_DEMUXER,MSGL_ERR,MSGTR_TooManyAudioInBuffer,demux->audio->packs,demux->audio->bytes);
+ mp_msg(MSGT_DEMUXER,MSGL_HINT,MSGTR_MaybeNI);
+ break;
+ }
+ if(demux->video->packs>=MAX_PACKS || demux->video->bytes>=MAX_PACK_BYTES){
+ mp_msg(MSGT_DEMUXER,MSGL_ERR,MSGTR_TooManyVideoInBuffer,demux->video->packs,demux->video->bytes);
+ mp_msg(MSGT_DEMUXER,MSGL_HINT,MSGTR_MaybeNI);
+ break;
+ }
+ if(!demux_fill_buffer(demux,ds)){
+ mp_dbg(MSGT_DEMUXER,MSGL_DBG2,"ds_fill_buffer()->demux_fill_buffer() failed\n");
+ break; // EOF
+ }
+ }
+ ds->buffer_pos=ds->buffer_size=0;
+ ds->buffer=NULL;
+ mp_msg(MSGT_DEMUXER,MSGL_V,"ds_fill_buffer: EOF reached (stream: %s) \n",ds==demux->audio?"audio":"video");
+ ds->eof=1;
+ return 0;
+}
+
+int demux_read_data(demux_stream_t *ds,unsigned char* mem,int len){
+int x;
+int bytes=0;
+while(len>0){
+ x=ds->buffer_size-ds->buffer_pos;
+ if(x==0){
+ if(!ds_fill_buffer(ds)) return bytes;
+ } else {
+ if(x>len) x=len;
+ if(mem) memcpy(mem+bytes,&ds->buffer[ds->buffer_pos],x);
+ bytes+=x;len-=x;ds->buffer_pos+=x;
+ }
+}
+return bytes;
+}
+
+int demux_read_data_pack(demux_stream_t *ds,unsigned char* mem,int len){
+int x;
+int bytes=0;
+while(len>0){
+ x=ds->buffer_size-ds->buffer_pos;
+ if(x==0){
+ if(!ds_fill_buffer(ds)) return bytes;
+ } else {
+ if(x>len) x=len;
+ if(mem) memcpy(mem+bytes,&ds->buffer[ds->buffer_pos],x);
+ bytes+=x;len-=x;ds->buffer_pos+=x;
+ return bytes; // stop at end of package! (for correct timestamping)
+ }
+}
+return bytes;
+}
+
+
+void ds_free_packs(demux_stream_t *ds){
+ demux_packet_t *dp=ds->first;
+ while(dp){
+ demux_packet_t *dn=dp->next;
+ free(dp->buffer);
+ free(dp);
+ dp=dn;
+ }
+ if(ds->asf_packet){
+ // free unfinished .asf fragments:
+ free(ds->asf_packet->buffer);
+ free(ds->asf_packet);
+ ds->asf_packet=NULL;
+ }
+ ds->first=ds->last=NULL;
+ ds->packs=0; // !!!!!
+ ds->bytes=0;
+ if(ds->buffer) free(ds->buffer);
+ ds->buffer=NULL;
+ ds->buffer_pos=ds->buffer_size;
+ ds->pts=0; ds->pts_bytes=0;
+}
+
+int ds_get_packet(demux_stream_t *ds,unsigned char **start){
+ while(1){
+ int len;
+ if(ds->buffer_pos>=ds->buffer_size){
+ if(!ds_fill_buffer(ds)){
+ // EOF
+ *start = NULL;
+ return -1;
+ }
+ }
+ len=ds->buffer_size-ds->buffer_pos;
+ *start = &ds->buffer[ds->buffer_pos];
+ ds->buffer_pos+=len;
+ return len;
+ }
+}
+
+int ds_get_packet_sub(demux_stream_t *ds,unsigned char **start){
+ while(1){
+ int len;
+ if(ds->buffer_pos>=ds->buffer_size){
+ *start = NULL;
+ if(!ds->packs) return -1; // no sub
+ if(!ds_fill_buffer(ds)) return -1; // EOF
+ }
+ len=ds->buffer_size-ds->buffer_pos;
+ *start = &ds->buffer[ds->buffer_pos];
+ ds->buffer_pos+=len;
+ return len;
+ }
+}
+
+// ====================================================================
+
+// feed-back from demuxers:
+extern int num_elementary_packets100; // for MPEG-ES fileformat detection
+extern int num_elementary_packets101;
+extern int num_elementary_packetsPES;
+extern int num_elementary_packets1B6;
+
+// commandline options, flags:
+//extern int seek_to_byte;
+extern int force_ni;
+extern int pts_from_bps;
+
+extern int audio_id;
+extern int video_id;
+extern int dvdsub_id;
+
+void read_avi_header(demuxer_t *demuxer,int index_mode);
+int asf_check_header(demuxer_t *demuxer);
+int read_asf_header(demuxer_t *demuxer);
+demux_stream_t* demux_avi_select_stream(demuxer_t *demux,unsigned int id);
+demuxer_t* demux_open_avi(demuxer_t* demuxer);
+int mov_check_file(demuxer_t* demuxer);
+int mov_read_header(demuxer_t* demuxer);
+
+
+demuxer_t* demux_open(stream_t *stream,int file_format,int audio_id,int video_id,int dvdsub_id){
+
+//int file_format=(*file_format_ptr);
+
+demuxer_t *demuxer=NULL;
+
+demux_stream_t *d_audio=NULL;
+demux_stream_t *d_video=NULL;
+
+sh_audio_t *sh_audio=NULL;
+sh_video_t *sh_video=NULL;
+
+//printf("demux_open(%p,%d,%d,%d,%d) \n",stream,file_format,audio_id,video_id,dvdsub_id);
+
+//=============== Try to open as AVI file: =================
+if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_AVI){
+ demuxer=new_demuxer(stream,DEMUXER_TYPE_AVI,audio_id,video_id,dvdsub_id);
+ { //---- RIFF header:
+ int id=stream_read_dword_le(demuxer->stream); // "RIFF"
+ if(id==mmioFOURCC('R','I','F','F')){
+ stream_read_dword_le(demuxer->stream); //filesize
+ id=stream_read_dword_le(demuxer->stream); // "AVI "
+ if(id==formtypeAVI){
+ mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_DetectedAVIfile);
+ file_format=DEMUXER_TYPE_AVI;
+ }
+ }
+ }
+}
+//=============== Try to open as ASF file: =================
+if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_ASF){
+ demuxer=new_demuxer(stream,DEMUXER_TYPE_ASF,audio_id,video_id,dvdsub_id);
+ if(asf_check_header(demuxer)){
+ mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_DetectedASFfile);
+ file_format=DEMUXER_TYPE_ASF;
+ }
+}
+//=============== Try to open as MPEG-PS file: =================
+if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_PS){
+ int pes=1;
+ while(pes>=0){
+ demuxer=new_demuxer(stream,DEMUXER_TYPE_MPEG_PS,audio_id,video_id,dvdsub_id);
+ if(!pes) demuxer->synced=1; // hack!
+ num_elementary_packets100=0;
+ num_elementary_packets101=0;
+ num_elementary_packets1B6=0;
+ num_elementary_packetsPES=0;
+
+ if(ds_fill_buffer(demuxer->video)){
+ if(!pes)
+ mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_DetectedMPEGPESfile);
+ else
+ mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_DetectedMPEGPSfile);
+ file_format=DEMUXER_TYPE_MPEG_PS;
+ } else {
+ // some hack to get meaningfull error messages to our unhappy users:
+ if(num_elementary_packets100>=2 && num_elementary_packets101>=2 &&
+ abs(num_elementary_packets101-num_elementary_packets100)<8){
+ if(num_elementary_packetsPES>=4 && num_elementary_packetsPES>=num_elementary_packets100-4){
+ --pes;continue; // tricky...
+ }
+ file_format=DEMUXER_TYPE_MPEG_ES; // <-- hack is here :)
+ } else {
+ if(demuxer->synced==2)
+ mp_msg(MSGT_DEMUXER,MSGL_ERR,"MPEG: " MSGTR_MissingVideoStreamBug);
+ else
+ mp_msg(MSGT_DEMUXER,MSGL_V,"Not MPEG System Stream format... (maybe Transport Stream?)\n");
+ }
+ }
+ break;
+ }
+}
+//=============== Try to open as MPEG-ES file: =================
+if(file_format==DEMUXER_TYPE_MPEG_ES){ // little hack, see above!
+ demuxer=new_demuxer(stream,DEMUXER_TYPE_MPEG_ES,audio_id,video_id,dvdsub_id);
+ if(!ds_fill_buffer(demuxer->video)){
+ mp_msg(MSGT_DEMUXER,MSGL_ERR,MSGTR_InvalidMPEGES);
+ file_format=DEMUXER_TYPE_UNKNOWN;
+ } else {
+ mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_DetectedMPEGESfile);
+ }
+}
+//=============== Try to open as MOV file: =================
+#if 1
+if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MOV){
+ demuxer=new_demuxer(stream,DEMUXER_TYPE_MOV,audio_id,video_id,dvdsub_id);
+ if(mov_check_file(demuxer)){
+ mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_DetectedQTMOVfile);
+ file_format=DEMUXER_TYPE_MOV;
+ }
+}
+#endif
+//=============== Unknown, exiting... ===========================
+if(file_format==DEMUXER_TYPE_UNKNOWN){
+ mp_msg(MSGT_DEMUXER,MSGL_ERR,MSGTR_FormatNotRecognized);
+ return NULL;
+// GUI_MSG( mplUnknowFileType )
+}
+//====== File format recognized, set up these for compatibility: =========
+d_audio=demuxer->audio;
+d_video=demuxer->video;
+//d_dvdsub=demuxer->sub;
+
+demuxer->file_format=file_format;
+
+switch(file_format){
+ case DEMUXER_TYPE_MOV: {
+ if(!mov_read_header(demuxer)) return NULL;
+// sh_video=d_video->sh;if(sh_video) sh_video->ds=d_video;
+// sh_audio=d_audio->sh;if(sh_audio) sh_audio->ds=d_audio;
+ break;
+ }
+ case DEMUXER_TYPE_AVI: {
+ return (demuxer_t*) demux_open_avi(demuxer);
+// break;
+ }
+ case DEMUXER_TYPE_ASF: {
+ //---- ASF header:
+ read_asf_header(demuxer);
+ stream_reset(demuxer->stream);
+ stream_seek(demuxer->stream,demuxer->movi_start);
+// demuxer->idx_pos=0;
+// demuxer->endpos=avi_header.movi_end;
+ if(!ds_fill_buffer(d_video)){
+ mp_msg(MSGT_DEMUXER,MSGL_WARN,"ASF: " MSGTR_MissingVideoStream);
+ sh_video=NULL;
+ //printf("ASF: missing video stream!? contact the author, it may be a bug :(\n");
+ //GUI_MSG( mplASFErrorMissingVideoStream )
+ } else {
+ sh_video=d_video->sh;sh_video->ds=d_video;
+ sh_video->fps=1000.0f; sh_video->frametime=0.001f; // 1ms
+ mp_msg(MSGT_DEMUXER,MSGL_INFO,"VIDEO: [%.4s] %ldx%ld %dbpp\n",
+ (char *)&sh_video->bih->biCompression,
+ sh_video->bih->biWidth,
+ sh_video->bih->biHeight,
+ sh_video->bih->biBitCount);
+// sh_video->i_bps=10*asf_packetsize; // FIXME!
+ }
+ if(audio_id!=-2){
+ mp_msg(MSGT_DEMUXER,MSGL_V,"ASF: Searching for audio stream (id:%d)\n",d_audio->id);
+ if(!ds_fill_buffer(d_audio)){
+ mp_msg(MSGT_DEMUXER,MSGL_INFO,"ASF: " MSGTR_MissingAudioStream);
+ sh_audio=NULL;
+ } else {
+ sh_audio=d_audio->sh;sh_audio->ds=d_audio;
+ sh_audio->format=sh_audio->wf->wFormatTag;
+ }
+ }
+ break;
+ }
+ case DEMUXER_TYPE_MPEG_ES: {
+ sh_audio=NULL; // ES streams has no audio channel
+ d_video->sh=new_sh_video(demuxer,0); // create dummy video stream header, id=0
+ sh_video=d_video->sh;sh_video->ds=d_video;
+ break;
+ }
+ case DEMUXER_TYPE_MPEG_PS: {
+ sh_video=d_video->sh;sh_video->ds=d_video;
+ if(demuxer->stream->type!=STREAMTYPE_VCD) demuxer->movi_start=0; // for VCD
+
+ if(audio_id!=-2) {
+ if(!ds_fill_buffer(d_audio)){
+ mp_msg(MSGT_DEMUXER,MSGL_INFO,"MPEG: " MSGTR_MissingAudioStream);
+ sh_audio=NULL;
+ } else {
+ sh_audio=d_audio->sh;sh_audio->ds=d_audio;
+ switch(d_audio->id & 0xE0){ // 1110 0000 b (high 3 bit: type low 5: id)
+ case 0x00: sh_audio->format=0x50;break; // mpeg
+ case 0xA0: sh_audio->format=0x10001;break; // dvd pcm
+ case 0x80: sh_audio->format=0x2000;break; // ac3
+ default: sh_audio=NULL; // unknown type
+ }
+ }
+ }
+ break;
+ }
+} // switch(file_format)
+
+return demuxer;
+}
+
+int demux_seek_avi(demuxer_t *demuxer,float rel_seek_secs,int flags);
+int demux_seek_asf(demuxer_t *demuxer,float rel_seek_secs,int flags);
+int demux_seek_mpg(demuxer_t *demuxer,float rel_seek_secs,int flags);
+void demux_seek_mov(demuxer_t *demuxer,float pts,int flags);
+
+int demux_seek(demuxer_t *demuxer,float rel_seek_secs,int flags){
+ demux_stream_t *d_audio=demuxer->audio;
+ demux_stream_t *d_video=demuxer->video;
+ sh_audio_t *sh_audio=d_audio->sh;
+ sh_video_t *sh_video=d_video->sh;
+
+if(!demuxer->seekable){
+ if(demuxer->file_format==DEMUXER_TYPE_AVI)
+ mp_msg(MSGT_SEEK,MSGL_WARN,MSGTR_CantSeekRawAVI);
+ else
+ mp_msg(MSGT_SEEK,MSGL_WARN,MSGTR_CantSeekFile);
+ return 0;
+}
+
+ // clear demux buffers:
+ if(sh_audio){ ds_free_packs(d_audio);sh_audio->a_buffer_len=0;}
+ ds_free_packs(d_video);
+
+ demuxer->stream->eof=0; // clear eof flag
+
+ if(sh_audio) sh_audio->timer=0;
+ sh_video->timer=0; // !!!!!!
+
+switch(demuxer->file_format){
+
+ case DEMUXER_TYPE_AVI:
+ demux_seek_avi(demuxer,rel_seek_secs,flags); break;
+
+ case DEMUXER_TYPE_ASF:
+ demux_seek_asf(demuxer,rel_seek_secs,flags); break;
+
+ case DEMUXER_TYPE_MPEG_ES:
+ case DEMUXER_TYPE_MPEG_PS:
+ demux_seek_mpg(demuxer,rel_seek_secs,flags); break;
+
+ case DEMUXER_TYPE_MOV:
+ demux_seek_mov(demuxer,rel_seek_secs,flags); break;
+
+} // switch(demuxer->file_format)
+
+return 1;
+}
+
+
diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h
new file mode 100644
index 0000000000..0cb3eea22e
--- /dev/null
+++ b/libmpdemux/demuxer.h
@@ -0,0 +1,155 @@
+
+#include "config.h"
+
+#define MAX_PACKS 4096
+#define MAX_PACK_BYTES 0x800000
+
+#define DEMUXER_TYPE_UNKNOWN 0
+#define DEMUXER_TYPE_MPEG_ES 1
+#define DEMUXER_TYPE_MPEG_PS 2
+#define DEMUXER_TYPE_AVI 3
+#define DEMUXER_TYPE_AVI_NI 4
+#define DEMUXER_TYPE_AVI_NINI 5
+#define DEMUXER_TYPE_ASF 6
+#define DEMUXER_TYPE_MOV 7
+
+#define DEMUXER_TIME_NONE 0
+#define DEMUXER_TIME_PTS 1
+#define DEMUXER_TIME_FILE 2
+#define DEMUXER_TIME_BPS 3
+
+
+// Holds one packet/frame/whatever
+typedef struct demux_packet_st {
+ int len;
+ float pts;
+ off_t pos; // position in index (AVI) or file (MPG)
+ unsigned char* buffer;
+ int flags; // keyframe, etc
+ struct demux_packet_st* next;
+} demux_packet_t;
+
+typedef struct {
+ int buffer_pos; // current buffer position
+ int buffer_size; // current buffer size
+ unsigned char* buffer; // current buffer
+ float pts; // current buffer's pts
+ int pts_bytes; // number of bytes read after last pts stamp
+ int eof; // end of demuxed stream? (true if all buffer empty)
+ off_t pos; // position in the input stream (file)
+ off_t dpos; // position in the demuxed stream
+ int pack_no; // serial number of packet
+ int flags; // flags of current packet (keyframe etc)
+//---------------
+ int packs; // number of packets in buffer
+ int bytes; // total bytes of packets in buffer
+ demux_packet_t *first; // read to current buffer from here
+ demux_packet_t *last; // append new packets from input stream to here
+ int id; // stream ID (for multiple audio/video streams)
+ struct demuxer_st *demuxer; // parent demuxer structure (stream handler)
+// ---- asf -----
+ demux_packet_t *asf_packet; // read asf fragments here
+ int asf_seq;
+// ---- stream header ----
+ void* sh;
+} demux_stream_t;
+
+typedef struct demuxer_st {
+ stream_t *stream;
+ int synced; // stream synced (used by mpeg)
+ off_t filepos; // input stream current pos.
+ int type; // demuxer type: mpeg PS, mpeg ES, avi, avi-ni, avi-nini, asf
+ int file_format; // file format: mpeg/avi/asf
+ off_t movi_start;
+ off_t movi_end;
+ int seekable; // flag
+ //
+ demux_stream_t *audio; // audio buffer/demuxer
+ demux_stream_t *video; // video buffer/demuxer
+ demux_stream_t *sub; // dvd subtitle buffer/demuxer
+
+ // stream headers:
+ void* a_streams[256]; // audio streams (sh_audio_t)
+ void* v_streams[256]; // video sterams (sh_video_t)
+ char s_streams[32]; // dvd subtitles (flag)
+
+ void* priv; // fileformat-dependent data
+} demuxer_t;
+
+inline static demux_packet_t* new_demux_packet(int len){
+ demux_packet_t* dp=malloc(sizeof(demux_packet_t));
+ dp->len=len;
+ dp->buffer=malloc(len);
+ dp->next=NULL;
+ dp->pts=0;
+ dp->pos=0;
+ dp->flags=0;
+ return dp;
+}
+
+inline static void free_demux_packet(demux_packet_t* dp){
+ free(dp->buffer);
+ free(dp);
+}
+
+demux_stream_t* new_demuxer_stream(struct demuxer_st *demuxer,int id);
+demuxer_t* new_demuxer(stream_t *stream,int type,int a_id,int v_id,int s_id);
+void free_demuxer_stream(demux_stream_t *ds);
+void free_demuxer(demuxer_t *demuxer);
+
+void ds_add_packet(demux_stream_t *ds,demux_packet_t* dp);
+void ds_read_packet(demux_stream_t *ds,stream_t *stream,int len,float pts,off_t pos,int flags);
+
+int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds);
+int ds_fill_buffer(demux_stream_t *ds);
+
+inline static off_t ds_tell(demux_stream_t *ds){
+ return (ds->dpos-ds->buffer_size)+ds->buffer_pos;
+}
+
+inline static int ds_tell_pts(demux_stream_t *ds){
+ return (ds->pts_bytes-ds->buffer_size)+ds->buffer_pos;
+}
+
+int demux_read_data(demux_stream_t *ds,unsigned char* mem,int len);
+int demux_read_data_pack(demux_stream_t *ds,unsigned char* mem,int len);
+
+#if 1
+#define demux_getc(ds) (\
+ (ds->buffer_pos<ds->buffer_size) ? ds->buffer[ds->buffer_pos++] \
+ :((!ds_fill_buffer(ds))? (-1) : ds->buffer[ds->buffer_pos++] ) )
+#else
+inline static int demux_getc(demux_stream_t *ds){
+ if(ds->buffer_pos>=ds->buffer_size){
+ if(!ds_fill_buffer(ds)){
+// printf("DEMUX_GETC: EOF reached!\n");
+ return -1; // EOF
+ }
+ }
+// printf("[%02X]",ds->buffer[ds->buffer_pos]);
+ return ds->buffer[ds->buffer_pos++];
+}
+#endif
+
+void ds_free_packs(demux_stream_t *ds);
+int ds_get_packet(demux_stream_t *ds,unsigned char **start);
+int ds_get_packet_sub(demux_stream_t *ds,unsigned char **start);
+
+
+static inline int avi_stream_id(unsigned int id){
+ unsigned char *p=(unsigned char *)&id;
+ unsigned char a,b;
+#if WORDS_BIGENDIAN
+ a=p[3]-'0'; b=p[2]-'0';
+#else
+ a=p[0]-'0'; b=p[1]-'0';
+#endif
+ if(a>9 || b>9) return 100; // invalid ID
+ return a*10+b;
+}
+
+demuxer_t* demux_open(stream_t *stream,int file_format,int aid,int vid,int sid);
+int demux_seek(demuxer_t *demuxer,float rel_seek_secs,int flags);
+
+
+
diff --git a/libmpdemux/dvdauth.c b/libmpdemux/dvdauth.c
new file mode 100644
index 0000000000..65801d6dda
--- /dev/null
+++ b/libmpdemux/dvdauth.c
@@ -0,0 +1,229 @@
+/* (C)2001 by LGB (Gabor Lenart), based on example programs in libcss
+ lgb@lgb.hu */
+
+/* don't do anything with this source if css support was not requested */
+#include "config.h"
+#ifdef HAVE_LIBCSS
+
+#include <stdio.h>
+#include <stdlib.h>
+//#include <string.h> // FIXME: conflicts with fs.h
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <css.h>
+#if CSS_MAJOR_VERSION > 0 || (CSS_MAJOR_VERSION == 0 && CSS_MINOR_VERSION > 1)
+# include <dvd.h>
+# undef OLD_CSS_API
+#else
+# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+# include <sys/dvdio.h>
+# elif defined(__linux__)
+# include <linux/cdrom.h>
+# elif defined(__sun)
+# include <sun/dvdio.h>
+# else
+# error "Need the DVD ioctls"
+# endif
+# define OLD_CSS_API 1
+#endif
+
+#include "dvdauth.h"
+
+
+#if OLD_CSS_API
+/*
+ * provide some backward compatibiliy macros to compile this
+ * code using the old libcss-0.1
+ */
+#define DVDHandle int
+#define DVDOpenFailed (-1)
+
+#define DVDAuth(hdl, s) ioctl(hdl, DVD_AUTH, s)
+#define DVDOpenDevice(path) open(path, O_RDONLY)
+#define DVDCloseDevice(hdl) close(hdl)
+#define CSSDVDisEncrypted(hdl) CSSisEncrypted(hdl)
+#define CSSDVDAuthDisc CSSAuthDisc
+/* Arghhh! Please think before you commit! You forget to check the return
+ value of path_to_lba (-1 for error) in this way ... - LGB */
+//#define CSSDVDAuthTitlePath(hdl,key_title,path) \
+// CSSAuthTitle(hdl,key_title,path_to_lba(path))
+
+#else /*OLD_CSS_API*/
+
+#define DVDHandle struct dvd_device *
+#define DVDOpenFailed NULL
+
+#endif /*OLD_CSS_API*/
+
+
+char *dvd_auth_device=NULL;
+char *dvd_device=NULL;
+char *dvd_raw_device=NULL;
+unsigned char key_disc[2048];
+unsigned char key_title[5];
+unsigned char *dvdimportkey=NULL;
+int descrambling=0;
+
+
+#if OLD_CSS_API
+/*
+ * With the old libcss-0.1 api, we have to find out the LBA for
+ * a title for title authentication.
+ */
+#ifdef __linux__
+#include <linux/fs.h>
+
+#ifndef FIBMAP
+#define FIBMAP 1
+#endif
+
+static int path_to_lba (char *path)
+{
+ int lba = 0;
+ char cmd[100];
+ FILE *fp;
+
+ snprintf(cmd,sizeof(cmd),"fibmap_mplayer %s",path);
+ fp=popen(cmd,"r");
+ if (fp) {
+ int ret;
+ bzero(cmd,sizeof(cmd));
+ fgets(cmd,99,fp);
+ if ((ret=pclose(fp)))
+ fprintf(stderr,"fibmap_mplayer: %s\n",*cmd?cmd:"no error info");
+ if(WIFEXITED(ret) && !WEXITSTATUS(ret))
+ lba=atoi(cmd);
+ else
+ fp=NULL;
+ }
+ if (!fp) {
+ int fd;
+ printf("fibmap_mplayer could not run, trying with ioctl() ...\n");
+ if ((fd = open(path, O_RDONLY)) == -1) {
+ fprintf(stderr, "Cannot open file %s: %s",
+ path ? path : "(NULL)", strerror(errno));
+ return -1;
+ }
+ if (ioctl(fd, FIBMAP, &lba) != 0) {
+ perror ("ioctl FIBMAP");
+ fprintf(stderr,"Hint: run mplayer as root (or better to install fibmap_mplayer as suid root)!\n");
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ }
+ printf("LBA: %d\n",lba);
+ return lba;
+}
+
+
+int CSSDVDAuthTitlePath(DVDHandle hdl,unsigned char *key_title,char *path)
+{
+ int lba=path_to_lba(path);
+ if (lba==-1) return -1;
+ return CSSAuthTitle(hdl,key_title,lba);
+}
+
+
+#else /*linux*/
+static int path_to_lba (char *path)
+{
+#warning translating pathname to iso9660 LBA is not supported on this platform
+ fprintf(stderr, "Translating pathname to iso9660 LBA is not supported on this platform\n");
+ return -1;
+}
+#endif /*linux*/
+#endif /*OLD_CSS_API*/
+
+
+static void reset_agids ( DVDHandle dvd )
+{
+ dvd_authinfo ai;
+ int i;
+ for (i = 0; i < 4; i++) {
+ memset(&ai, 0, sizeof(ai));
+ ai.type = DVD_INVALIDATE_AGID;
+ ai.lsa.agid = i;
+ DVDAuth(dvd, &ai);
+ }
+}
+
+
+int dvd_import_key ( unsigned char *hexkey )
+{
+ unsigned char *t=key_title;
+ int digit=4,len;
+ bzero(key_title,sizeof(key_title));
+// printf("DVD key: %s\n",hexkey);
+ for (len=0;len<10;len++) {
+// printf("-> %c\n",*hexkey);
+ if (!*hexkey) return 1;
+ if (*hexkey>='A'&&*hexkey<='F') *t|=(*hexkey-'A'+10)<<digit;
+ else if (*hexkey>='0'&&*hexkey<='9') *t|=(*hexkey-'0')<<digit;
+ else return 1;
+ if (digit) digit=0; else {
+ digit=4;
+ t++;
+ }
+ hexkey++;
+ }
+ if (*hexkey) return 1;
+ printf("DVD key (requested): %02X%02X%02X%02X%02X\n",key_title[0],key_title[1],key_title[2],key_title[3],key_title[4]);
+ descrambling=1;
+ return 0;
+}
+
+
+
+int dvd_auth ( char *dev , char *filename )
+{
+ DVDHandle dvd; /* DVD device handle */
+
+ if ((dvd=DVDOpenDevice(dev)) == DVDOpenFailed) {
+ fprintf(stderr,"DVD: cannot open DVD device \"%s\": %s.\n",
+ dev, strerror(errno));
+ return 1;
+ }
+
+ if (!CSSDVDisEncrypted(dvd)) {
+ printf("DVD is unencrypted! Skipping authentication!\n(note: you should not use -dvd switch for unencrypted discs!)\n");
+ DVDCloseDevice(dvd);
+ return 0;
+ } else printf("DVD is encrypted, issuing authentication ...\n");
+
+ /* reset AGIDs */
+ reset_agids(dvd);
+
+ /* authenticate disc */
+ if (CSSDVDAuthDisc(dvd,key_disc)) {
+ fprintf(stderr,"DVD: CSSDVDAuthDisc() failed.\n");
+ DVDCloseDevice(dvd);
+ return 1;
+ }
+
+ if (CSSDVDAuthTitlePath(dvd,key_title,filename)) {
+ fprintf(stderr,"DVD: CSSDVDAuthTitle() failed.\n");
+ DVDCloseDevice(dvd);
+ return 1;
+ }
+
+ /* decrypting title */
+ if (CSSDecryptTitleKey (key_title, key_disc) < 0) {
+ fprintf(stderr,"DVD: CSSDecryptTitleKey() failed.\n");
+ DVDCloseDevice(dvd);
+ return 1;
+ }
+
+ DVDCloseDevice(dvd);
+ printf("DVD title key is: %02X%02X%02X%02X%02X\n",key_title[0],key_title[1],key_title[2],key_title[3],key_title[4]);
+ descrambling=1;
+ return 0;
+}
+
+
+#endif
diff --git a/libmpdemux/dvdauth.h b/libmpdemux/dvdauth.h
new file mode 100644
index 0000000000..68ad752c0a
--- /dev/null
+++ b/libmpdemux/dvdauth.h
@@ -0,0 +1,16 @@
+//#include "config.h"
+#ifdef HAVE_LIBCSS
+#ifndef _MPLAYER_CSS_H
+#define _MPLAYER_CSS_H
+
+extern char *dvd_auth_device;
+extern unsigned char key_disc[];
+extern unsigned char key_title[];
+extern unsigned char *dvdimportkey;
+extern int descrambling;
+
+int dvd_auth ( char *, char * );
+int dvd_import_key ( unsigned char * );
+
+#endif
+#endif
diff --git a/libmpdemux/help_mp.h b/libmpdemux/help_mp.h
new file mode 100644
index 0000000000..c714314853
--- /dev/null
+++ b/libmpdemux/help_mp.h
@@ -0,0 +1 @@
+#include "../help_mp.h"
diff --git a/libmpdemux/http.c b/libmpdemux/http.c
new file mode 100644
index 0000000000..75157fccf0
--- /dev/null
+++ b/libmpdemux/http.c
@@ -0,0 +1,296 @@
+/*
+ * HTTP Helper
+ * by Bertrand Baudet <bertrand_baudet@yahoo.com>
+ * (C) 2001, MPlayer team.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "http.h"
+
+HTTP_header_t *
+http_new_header() {
+ HTTP_header_t *http_hdr;
+
+ http_hdr = (HTTP_header_t*)malloc(sizeof(HTTP_header_t));
+ if( http_hdr==NULL ) return NULL;
+ memset( http_hdr, 0, sizeof(HTTP_header_t) );
+
+ return http_hdr;
+}
+
+void
+http_free( HTTP_header_t *http_hdr ) {
+ int i;
+ if( http_hdr==NULL ) return;
+ if( http_hdr->protocol!=NULL ) free( http_hdr->protocol );
+ if( http_hdr->uri!=NULL ) free( http_hdr->uri );
+ if( http_hdr->reason_phrase!=NULL ) free( http_hdr->reason_phrase );
+ if( http_hdr->body!=NULL ) free( http_hdr->body );
+ if( http_hdr->field_search!=NULL ) free( http_hdr->field_search );
+ if( http_hdr->method!=NULL ) free( http_hdr->method );
+ if( http_hdr->buffer!=NULL ) free( http_hdr->buffer );
+ for( i=0 ; i<http_hdr->field_nb ; i++ )
+ if( http_hdr->fields[i]!=NULL ) free( http_hdr->fields[i] );
+ free( http_hdr );
+}
+
+int
+http_response_append( HTTP_header_t *http_hdr, char *response, int length ) {
+ char *ptr = NULL;
+ if( http_hdr==NULL || response==NULL || length<0 ) return -1;
+ ptr = (char*)malloc( http_hdr->buffer_size+length );
+ if( ptr==NULL ) {
+ printf("Memory allocation failed\n");
+ return -1;
+ }
+ if( http_hdr->buffer_size==0 ) {
+ // Buffer empty, copy response into it.
+ memcpy( ptr, response, length );
+ http_hdr->buffer_size = length;
+ } else {
+ // Buffer not empty, grow buffer, copy and append the response.
+ memcpy( ptr, http_hdr->buffer, http_hdr->buffer_size );
+ free( http_hdr->buffer );
+ memcpy( ptr+http_hdr->buffer_size, response, length );
+ http_hdr->buffer_size += length;
+ }
+ http_hdr->buffer = ptr;
+ return http_hdr->buffer_size;
+}
+
+int
+http_is_header_entired( HTTP_header_t *http_hdr ) {
+ if( http_hdr==NULL ) return -1;
+
+ if( strstr(http_hdr->buffer, "\r\n\r\n")==NULL ) return 0;
+ else return 1;
+}
+
+int
+http_response_parse( HTTP_header_t *http_hdr ) {
+ char *hdr_ptr, *ptr;
+ char *field=NULL;
+ int pos_hdr_sep, len;
+ if( http_hdr==NULL ) return -1;
+ if( http_hdr->is_parsed ) return 0;
+
+ // Get the protocol
+ hdr_ptr = strstr( http_hdr->buffer, " " );
+ if( hdr_ptr==NULL ) {
+ printf("Malformed answer. No space separator found.\n");
+ return -1;
+ }
+ len = hdr_ptr-http_hdr->buffer;
+ http_hdr->protocol = (char*)malloc(len+1);
+ if( http_hdr->protocol==NULL ) {
+ printf("Memory allocation failed\n");
+ return -1;
+ }
+ strncpy( http_hdr->protocol, http_hdr->buffer, len );
+ http_hdr->protocol[len]='\0';
+ if( !strncasecmp( http_hdr->protocol, "HTTP", 4) ) {
+ if( sscanf( http_hdr->protocol+5,"1.%d", &(http_hdr->http_minor_version) )!=1 ) {
+ printf("Malformed answer. Unable to get HTTP minor version.\n");
+ return -1;
+ }
+ }
+
+ // Get the status code
+ if( sscanf( ++hdr_ptr, "%d", &(http_hdr->status_code) )!=1 ) {
+ printf("Malformed answer. Unable to get status code.\n");
+ return -1;
+ }
+ hdr_ptr += 4;
+
+ // Get the reason phrase
+ ptr = strstr( hdr_ptr, "\r\n" );
+ if( hdr_ptr==NULL ) {
+ printf("Malformed answer. Unable to get the reason phrase.\n");
+ return -1;
+ }
+ len = ptr-hdr_ptr;
+ http_hdr->reason_phrase = (char*)malloc(len+1);
+ if( http_hdr->reason_phrase==NULL ) {
+ printf("Memory allocation failed\n");
+ return -1;
+ }
+ strncpy( http_hdr->reason_phrase, hdr_ptr, len );
+ http_hdr->reason_phrase[len]='\0';
+
+ // Set the position of the header separator: \r\n\r\n
+ ptr = strstr( http_hdr->buffer, "\r\n\r\n" );
+ if( ptr==NULL ) {
+ printf("Header may be incomplete. No CRLF CRLF found.\n");
+ return -1;
+ }
+ pos_hdr_sep = ptr-http_hdr->buffer;
+
+ hdr_ptr = strstr( http_hdr->buffer, "\r\n" )+2;
+ do {
+ ptr = strstr( hdr_ptr, "\r\n");
+ if( ptr==NULL ) {
+ printf("No CRLF found\n");
+ return -1;
+ }
+ len = ptr-hdr_ptr;
+ field = (char*)realloc(field, len+1);
+ if( field==NULL ) {
+ printf("Memory allocation failed\n");
+ return -1;
+ }
+ strncpy( field, hdr_ptr, len );
+ field[len]='\0';
+ http_set_field( http_hdr, field );
+ hdr_ptr = ptr+2;
+ } while( hdr_ptr<(http_hdr->buffer+pos_hdr_sep) );
+
+ if( field!=NULL ) free( field );
+
+ if( pos_hdr_sep+4<http_hdr->buffer_size ) {
+ // Response has data!
+ int data_length = http_hdr->buffer_size-(pos_hdr_sep+4);
+ http_hdr->body = (char*)malloc( data_length );
+ if( http_hdr->body==NULL ) {
+ printf("Memory allocation failed\n");
+ return -1;
+ }
+ memcpy( http_hdr->body, http_hdr->buffer+pos_hdr_sep+4, data_length );
+ http_hdr->body_size = data_length;
+ }
+
+ http_hdr->is_parsed = 1;
+ return 0;
+}
+
+char *
+http_build_request( HTTP_header_t *http_hdr ) {
+ char *ptr;
+ int i;
+ int len;
+ if( http_hdr==NULL ) return NULL;
+
+ if( http_hdr->method==NULL ) http_set_method( http_hdr, "GET");
+ if( http_hdr->uri==NULL ) http_set_uri( http_hdr, "/");
+
+ // Compute the request length
+ len = strlen(http_hdr->method)+strlen(http_hdr->uri)+12; // Method line
+ for( i=0 ; i<http_hdr->field_nb ; i++ ) // Fields
+ len += strlen(http_hdr->fields[i])+2;
+ len += 2; // CRLF
+ if( http_hdr->body!=NULL ) {
+ len += http_hdr->body_size;
+ }
+ if( http_hdr->buffer!=NULL ) {
+ free( http_hdr->buffer );
+ http_hdr->buffer = NULL;
+ }
+ http_hdr->buffer = (char*)malloc(len);
+ if( http_hdr->buffer==NULL ) {
+ printf("Memory allocation failed\n");
+ return NULL;
+ }
+ http_hdr->buffer_size = len;
+
+ ptr = http_hdr->buffer;
+ ptr += sprintf( ptr, "%s %s HTTP/1.%d\r\n", http_hdr->method, http_hdr->uri, http_hdr->http_minor_version );
+ for( i=0 ; i<http_hdr->field_nb ; i++ )
+ ptr += sprintf( ptr, "%s\r\n", http_hdr->fields[i] );
+ ptr += sprintf( ptr, "\r\n" );
+ if( http_hdr->body!=NULL ) {
+ memcpy( ptr, http_hdr->body, http_hdr->body_size );
+ }
+ return http_hdr->buffer;
+}
+
+char *
+http_get_field( HTTP_header_t *http_hdr, const char *field_name ) {
+ if( http_hdr==NULL || field_name==NULL ) return NULL;
+ http_hdr->search_pos = 0;
+ if( http_hdr->field_search!=NULL ) free( http_hdr->field_search );
+ http_hdr->field_search = (char*)malloc(strlen(field_name)+1);
+ if( http_hdr->field_search==NULL ) {
+ printf("Memory allocation failed\n");
+ return NULL;
+ }
+ strcpy( http_hdr->field_search, field_name );
+ return http_get_next_field( http_hdr );
+}
+
+char *
+http_get_next_field( HTTP_header_t *http_hdr ) {
+ char *ptr;
+ int i;
+ if( http_hdr==NULL ) return NULL;
+
+ for( i=http_hdr->search_pos ; i<http_hdr->field_nb ; i++ ) {
+ ptr = strstr( http_hdr->fields[i], ":" );
+ if( ptr==NULL ) return NULL;
+ if( !strncasecmp( http_hdr->fields[i], http_hdr->field_search, ptr-http_hdr->fields[i] ) ) {
+ ptr++; // Skip the column
+ while( ptr[0]==' ' ) ptr++; // Skip the spaces if there is some
+ http_hdr->search_pos = i+1;
+ return ptr; // return the value without the field name
+ }
+ }
+ return NULL;
+}
+
+void
+http_set_field( HTTP_header_t *http_hdr, const char *field ) {
+ int pos;
+ if( http_hdr==NULL || field==NULL ) return;
+
+ pos = http_hdr->field_nb;
+
+ http_hdr->fields[pos] = (char*)malloc(strlen(field)+1);
+ if( http_hdr->fields[pos]==NULL ) {
+ printf("Memory allocation failed\n");
+ return;
+ }
+ http_hdr->field_nb++;
+ strcpy( http_hdr->fields[pos], field );
+}
+
+void
+http_set_method( HTTP_header_t *http_hdr, const char *method ) {
+ if( http_hdr==NULL || method==NULL ) return;
+
+ http_hdr->method = (char*)malloc(strlen(method)+1);
+ if( http_hdr->method==NULL ) {
+ printf("Memory allocation failed\n");
+ return;
+ }
+ strcpy( http_hdr->method, method );
+}
+
+void
+http_set_uri( HTTP_header_t *http_hdr, const char *uri ) {
+ if( http_hdr==NULL || uri==NULL ) return;
+
+ http_hdr->uri = (char*)malloc(strlen(uri)+1);
+ if( http_hdr->uri==NULL ) {
+ printf("Memory allocation failed\n");
+ return;
+ }
+ strcpy( http_hdr->uri, uri );
+}
+
+void
+http_debug_hdr( HTTP_header_t *http_hdr ) {
+ int i;
+ if( http_hdr==NULL ) return;
+
+ printf("protocol: %s\n", http_hdr->protocol );
+ printf("http minor version: %d\n", http_hdr->http_minor_version );
+ printf("uri: %s\n", http_hdr->uri );
+ printf("method: %s\n", http_hdr->method );
+ printf("status code: %d\n", http_hdr->status_code );
+ printf("reason phrase: %s\n", http_hdr->reason_phrase );
+
+ printf("Fields:\n");
+ for( i=0 ; i<http_hdr->field_nb ; i++ )
+ printf(" %d - %s\n", i, http_hdr->fields[i] );
+}
diff --git a/libmpdemux/http.h b/libmpdemux/http.h
new file mode 100644
index 0000000000..f8919288ae
--- /dev/null
+++ b/libmpdemux/http.h
@@ -0,0 +1,44 @@
+/*
+ * HTTP Helper
+ * by Bertrand Baudet <bertrand_baudet@yahoo.com>
+ * (C) 2001, MPlayer team.
+ */
+
+#ifndef __HTTP_H
+#define __HTTP_H
+
+#define HTTP_FIELD_MAX 20
+
+typedef struct {
+ char *protocol;
+ char *method;
+ char *uri;
+ int status_code;
+ char *reason_phrase;
+ int http_minor_version;
+ char *fields[HTTP_FIELD_MAX];
+ int field_nb;
+ char *field_search;
+ int search_pos;
+ char *body;
+ int body_size;
+ char *buffer;
+ int buffer_size;
+ int is_parsed;
+} HTTP_header_t;
+
+HTTP_header_t* http_new_header();
+void http_free( HTTP_header_t *http_hdr );
+int http_response_append( HTTP_header_t *http_hdr, char *data, int length );
+int http_response_parse( HTTP_header_t *http_hdr );
+int http_is_header_entired( HTTP_header_t *http_hdr );
+char* http_build_request( HTTP_header_t *http_hdr );
+char* http_get_field( HTTP_header_t *http_hdr, const char *field_name );
+char* http_get_next_field( HTTP_header_t *http_hdr );
+void http_set_field( HTTP_header_t *http_hdr, const char *field );
+void http_set_method( HTTP_header_t *http_hdr, const char *method );
+void http_set_uri( HTTP_header_t *http_hdr, const char *uri );
+
+void http_debug_hdr( HTTP_header_t *http_hdr );
+
+#endif // __HTTP_H
diff --git a/libmpdemux/mp_msg.h b/libmpdemux/mp_msg.h
new file mode 100644
index 0000000000..0f8ceae361
--- /dev/null
+++ b/libmpdemux/mp_msg.h
@@ -0,0 +1,2 @@
+/* Let it be for now*/
+#include "../mp_msg.h"
diff --git a/libmpdemux/network.c b/libmpdemux/network.c
new file mode 100644
index 0000000000..45299b8e4d
--- /dev/null
+++ b/libmpdemux/network.c
@@ -0,0 +1,592 @@
+/*
+ * Network layer for MPlayer
+ * by Bertrand BAUDET <bertrand_baudet@yahoo.com>
+ * (C) 2001, MPlayer team.
+ */
+
+//#define DUMP2FILE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <pthread.h>
+
+#include <errno.h>
+#include <ctype.h>
+
+#include "stream.h"
+#include "demuxer.h"
+
+#include "network.h"
+#include "http.h"
+#include "url.h"
+#include "asf.h"
+
+streaming_ctrl_t *streaming_ctrl;
+
+static ASF_StreamType_e streaming_type = ASF_Unknown_e;
+
+Net_Fifo *
+net_fifo_new() {
+ Net_Fifo *net_fifo;
+ net_fifo = (Net_Fifo*)malloc(sizeof(Net_Fifo));
+ if( net_fifo==NULL ) {
+ printf("Memory allocation failed\n");
+ return NULL;
+ }
+ memset( net_fifo, 0, sizeof(Net_Fifo) );
+ return net_fifo;
+}
+
+void
+net_fifo_free( Net_Fifo *net_fifo ) {
+ if( net_fifo->buffer!=NULL ) free( net_fifo->buffer );
+ free( net_fifo );
+}
+
+int
+net_fifo_push(Net_Fifo *net_fifo, char *buffer, int length ) {
+ char *ptr;
+ if( net_fifo==NULL || buffer==NULL || length<0 ) return -1;
+
+ ptr = (char*)malloc(length+net_fifo->length);
+ if( ptr==NULL ) {
+ printf("Memory allocation failed\n");
+ return -1;
+ }
+ if( net_fifo->buffer!=NULL ) {
+ memcpy( ptr, net_fifo->buffer, net_fifo->length );
+ free( net_fifo->buffer );
+ }
+ memcpy( ptr+net_fifo->length, buffer, length );
+ net_fifo->buffer = ptr;
+ net_fifo->length += length;
+ return net_fifo->length;
+}
+
+int
+net_fifo_pop(Net_Fifo *net_fifo, char *buffer, int length ) {
+ char *ptr;
+ int len;
+ if( net_fifo==NULL || buffer==NULL || length<0 ) return -1;
+ if( net_fifo->buffer==NULL || net_fifo->length==0 ) return -1;
+
+ len = MIN(net_fifo->length, length);
+
+ ptr = (char*)malloc(net_fifo->length-len);
+ if( ptr==NULL ) {
+ printf("Memory allocation failed\n");
+ return -1;
+ }
+ memcpy( buffer, net_fifo->buffer, len );
+ if( net_fifo->length-len!=0 ) {
+ memcpy( ptr, net_fifo->buffer+len, net_fifo->length-len );
+ free( net_fifo->buffer );
+ net_fifo->buffer = ptr;
+ net_fifo->length -= len;
+ } else {
+ free( net_fifo->buffer );
+ net_fifo->buffer = NULL;
+ net_fifo->length = 0;
+ }
+ return len;
+}
+
+streaming_ctrl_t *
+streaming_ctrl_new( ) {
+ streaming_ctrl_t *streaming_ctrl;
+ streaming_ctrl = (streaming_ctrl_t*)malloc(sizeof(streaming_ctrl_t));
+ if( streaming_ctrl==NULL ) {
+ printf("Failed to allocate memory\n");
+ return NULL;
+ }
+ memset( streaming_ctrl, 0, sizeof(streaming_ctrl_t) );
+ streaming_ctrl->buffer = net_fifo_new();
+ return streaming_ctrl;
+}
+
+void
+streaming_ctrl_free( streaming_ctrl_t *streaming_ctrl ) {
+ if( streaming_ctrl==NULL ) return;
+ if( streaming_ctrl->buffer!=NULL ) net_fifo_free( streaming_ctrl->buffer );
+ free( streaming_ctrl );
+}
+
+int
+readFromServer(int fd, char *buffer, int length) {
+ int ret;
+ int done=0;
+ fd_set set;
+ struct timeval tv;
+ if( buffer==NULL || length<0 ) return -1;
+
+
+// fcntl( fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK );
+ return read( fd, buffer, length );
+
+ do {
+ tv.tv_sec = 0;
+ tv.tv_usec = 10000; // 10 milli-seconds timeout
+ FD_ZERO( &set );
+ FD_SET( fd, &set );
+ ret = select( fd+1, &set, NULL, NULL, &tv );
+ if( ret<0 ) {
+ perror("select");
+ } else if( ret==0 ) {
+ printf("timeout\n");
+ }
+ if( FD_ISSET(fd, &set) ) {
+ ret = read( fd, buffer, length );
+ if( ret<0 ) {
+ if( errno!=EINPROGRESS ) {
+ }
+ } else {
+ done = 1;
+ }
+ } else {
+ return -1;
+ }
+ } while( !done );
+
+ return ret;
+}
+
+// Connect to a server using a TCP connection
+int
+connect2Server(char *host, int port) {
+ int socket_server_fd;
+ int err, err_len;
+ fd_set set;
+ struct timeval tv;
+ struct sockaddr_in server_address;
+
+ printf("Connecting to server %s:%d ...\n", host, port );
+
+ socket_server_fd = socket(AF_INET, SOCK_STREAM, 0);
+// fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK );
+ if( socket_server_fd==-1 ) {
+ perror("Failed to create socket");
+ return -1;
+ }
+
+ if( isalpha(host[0]) ) {
+ struct hostent *hp =(struct hostent*)gethostbyname( host );
+ if( hp==NULL ) {
+ printf("Counldn't resolve name: %s\n", host);
+ return -1;
+ }
+ memcpy( (void*)&server_address.sin_addr.s_addr, (void*)hp->h_addr, hp->h_length );
+ } else {
+ inet_pton(AF_INET, host, &server_address.sin_addr);
+ }
+ server_address.sin_family=AF_INET;
+ server_address.sin_port=htons(port);
+
+ if( connect( socket_server_fd, (struct sockaddr*)&server_address, sizeof(server_address) )==-1 ) {
+ if( errno!=EINPROGRESS ) {
+ perror("Failed to connect to server");
+ close(socket_server_fd);
+ return -1;
+ }
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 10000; // 10 milli-seconds timeout
+ FD_ZERO( &set );
+ FD_SET( socket_server_fd, &set );
+ if( select(socket_server_fd+1, NULL, &set, NULL, &tv)>0 ) {
+ err_len = sizeof( err );
+ getsockopt( socket_server_fd, SOL_SOCKET, SO_ERROR, &err, &err_len );
+ if( err ) {
+ printf("Couldn't connect to host %s\n", host );
+ printf("Socket error: %d\n", err );
+ close(socket_server_fd);
+ return -1;
+ }
+ }
+ return socket_server_fd;
+}
+
+int
+http_send_request( URL_t *url ) {
+ HTTP_header_t *http_hdr;
+ int fd;
+ http_hdr = http_new_header();
+ http_set_uri( http_hdr, url->file );
+ http_set_field( http_hdr, "User-Agent: MPlayer");
+ http_set_field( http_hdr, "Connection: closed");
+ if( http_build_request( http_hdr )==NULL ) {
+ return -1;
+ }
+
+ fd = connect2Server( url->hostname, url->port );
+ if( fd<0 ) {
+ return -1;
+ }
+ write( fd, http_hdr->buffer, http_hdr->buffer_size );
+ http_free( http_hdr );
+
+ return fd;
+}
+
+HTTP_header_t *
+http_read_response( int fd ) {
+ HTTP_header_t *http_hdr;
+ char response[BUFFER_SIZE];
+ int i;
+
+ http_hdr = http_new_header();
+ if( http_hdr==NULL ) {
+ return NULL;
+ }
+
+ do {
+ i = readFromServer( fd, response, BUFFER_SIZE );
+ if( i<0 ) {
+ printf("Read failed\n");
+ }
+ http_response_append( http_hdr, response, i );
+ } while( !http_is_header_entired( http_hdr ) );
+ http_response_parse( http_hdr );
+ return http_hdr;
+}
+
+// By using the protocol, the extension of the file or the content-type
+// we might be able to guess the streaming type.
+int
+autodetectProtocol(URL_t *url, int *fd_out) {
+ HTTP_header_t *http_hdr;
+ int fd=-1;
+ int i;
+ int redirect;
+ char *extension;
+ char *content_type;
+ char *next_url;
+ char response[1024];
+
+ do {
+ *fd_out=-1;
+ next_url = NULL;
+ extension = NULL;
+ content_type = NULL;
+ redirect = 0;
+
+ if( url==NULL ) return DEMUXER_TYPE_UNKNOWN;
+
+ // Get the extension of the file if present
+ if( url->file!=NULL ) {
+ for( i=strlen(url->file) ; i>0 ; i-- ) {
+ if( url->file[i]=='.' ) {
+ extension=(url->file)+i+1;
+ break;
+ }
+ }
+ }
+// extension=NULL;
+ if( extension!=NULL ) {
+ printf("Extension: %s\n", extension );
+ if( !strcasecmp(extension, "asf") ||
+ !strcasecmp(extension, "wmv") ||
+ !strcasecmp(extension, "asx") ) {
+ if( url->port==0 ) url->port = 80;
+ return DEMUXER_TYPE_ASF;
+ }
+ if( !strcasecmp(extension, "mpg") ||
+ !strcasecmp(extension, "mpeg") ) {
+ if( url->port==0 ) url->port = 80;
+ return DEMUXER_TYPE_MPEG_PS;
+ }
+ if( !strcasecmp(extension, "avi") ) {
+ if( url->port==0 ) url->port = 80;
+ return DEMUXER_TYPE_AVI;
+ }
+ }
+
+ // Checking for RTSP
+ if( !strcasecmp(url->protocol, "rtsp") ) {
+ printf("RTSP protocol not yet implemented!\n");
+ return DEMUXER_TYPE_UNKNOWN;
+ }
+
+ // Checking for ASF
+ if( !strcasecmp(url->protocol, "mms") ) {
+ if( url->port==0 ) url->port = 80;
+ return DEMUXER_TYPE_ASF;
+ }
+
+ // HTTP based protocol
+ if( !strcasecmp(url->protocol, "http") ) {
+ if( url->port==0 ) url->port = 80;
+
+ fd = http_send_request( url );
+ if( fd<0 ) {
+ *fd_out=-1;
+ return DEMUXER_TYPE_UNKNOWN;
+ }
+
+ http_hdr = http_read_response( fd );
+ if( http_hdr==NULL ) {
+ close( fd );
+ *fd_out=-1;
+ return DEMUXER_TYPE_UNKNOWN;
+ }
+
+ *fd_out=fd;
+ //http_debug_hdr( http_hdr );
+
+ // Check if the response is an ICY status_code reason_phrase
+ if( !strcasecmp(http_hdr->protocol, "ICY") ) {
+ // Ok, we have detected an mp3 streaming
+ return DEMUXER_TYPE_MPEG_PS;
+ }
+
+ switch( http_hdr->status_code ) {
+ case 200: // OK
+ // Look if we can use the Content-Type
+ content_type = http_get_field( http_hdr, "Content-Type" );
+ if( content_type!=NULL ) {
+ printf("Content-Type: [%s]\n", content_type );
+ printf("Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length") );
+ // Check for ASF
+ if( asf_http_streaming_type(content_type, NULL)!=ASF_Unknown_e ) {
+ return DEMUXER_TYPE_ASF;
+ }
+ // Check for MP3 streaming
+ // Some MP3 streaming server answer with audio/mpeg
+ if( !strcasecmp(content_type, "audio/mpeg") ) {
+ return DEMUXER_TYPE_MPEG_PS;
+ }
+ // Check for MPEG streaming
+ if( !strcasecmp(content_type, "video/mpeg") ) {
+ return DEMUXER_TYPE_MPEG_PS;
+ }
+ // AVI ??? => video/x-msvideo
+ if( !strcasecmp(content_type, "video/x-msvideo") ) {
+ return DEMUXER_TYPE_AVI;
+ }
+ }
+ break;
+ // Redirect
+ case 301: // Permanently
+ case 302: // Temporarily
+ // TODO: RFC 2616, recommand to detect infinite redirection loops
+ next_url = http_get_field( http_hdr, "Location" );
+ if( next_url!=NULL ) {
+ close( fd );
+ url_free( url );
+ url = url_new( next_url );
+ redirect = 1;
+ }
+ break;
+ default:
+ printf("Server returned %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase );
+ close( fd );
+ *fd_out=-1;
+ return DEMUXER_TYPE_UNKNOWN;
+ }
+ }
+ } while( redirect );
+
+ return DEMUXER_TYPE_UNKNOWN;
+}
+
+int
+nop_streaming_read( streaming_ctrl_t *streaming_ctrl ) {
+ char *buffer;
+ int len;
+ if( streaming_ctrl==NULL ) return -1;
+ len = streaming_ctrl->buffer->length;
+ if( len==0 ) return 0;
+
+ buffer = (char*)malloc( len );
+ if( buffer==NULL ) {
+ printf("Memory allocation failed\n");
+ return -1;
+ }
+ net_fifo_pop( streaming_ctrl->buffer, buffer, len );
+ write( streaming_ctrl->fd_pipe_in, buffer, len );
+ free( buffer );
+ return len;
+}
+
+int
+nop_streaming_start( streaming_ctrl_t *streaming_ctrl ) {
+ HTTP_header_t *http_hdr;
+ int fd;
+ if( streaming_ctrl==NULL ) return -1;
+
+ fd = streaming_ctrl->fd_net;
+ if( fd<0 ) {
+ fd = http_send_request( *(streaming_ctrl->url) );
+ if( fd<0 ) return -1;
+ http_hdr = http_read_response( fd );
+ if( http_hdr==NULL ) return -1;
+
+ switch( http_hdr->status_code ) {
+ case 200: // OK
+ printf("Content-Type: [%s]\n", http_get_field(http_hdr, "Content-Type") );
+ printf("Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length") );
+ if( http_hdr->body_size>0 ) {
+ write( streaming_ctrl->fd_pipe_in, http_hdr->body, http_hdr->body_size );
+ }
+ break;
+ default:
+ printf("Server return %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase );
+ close( fd );
+ fd = -1;
+ }
+ streaming_ctrl->fd_net = fd;
+ }
+
+ http_free( http_hdr );
+
+ streaming_ctrl->streaming_read = nop_streaming_read;
+ streaming_ctrl->prebuffer_size = 180000;
+// streaming_ctrl->prebuffer_size = 0;
+ streaming_ctrl->buffering = 1;
+// streaming_ctrl->buffering = 0;
+ streaming_ctrl->status = streaming_playing_e;
+ return fd;
+}
+
+void
+network_streaming(void *arg) {
+ char buffer[BUFFER_SIZE];
+ fd_set fd_net_in;
+ int ret;
+
+ arg = arg;
+
+ do {
+ FD_ZERO( &fd_net_in );
+ FD_SET( streaming_ctrl->fd_net, &fd_net_in );
+
+ ret = select( streaming_ctrl->fd_net+1, &fd_net_in, NULL, NULL, NULL );
+ if( ret<0 ) {
+ perror("select");
+ return; //exit(1); // FIXME!
+ }
+ if( FD_ISSET( streaming_ctrl->fd_net, &fd_net_in ) ) {
+ ret = readFromServer( streaming_ctrl->fd_net, buffer, BUFFER_SIZE );
+ if( ret<=0 ) {
+ streaming_ctrl->status=streaming_stopped_e;
+ } else {
+//printf(" push: 0x%02X\n", *((unsigned int*)buffer) );
+ net_fifo_push( streaming_ctrl->buffer, buffer, ret );
+ if( !streaming_ctrl->buffering ) {
+ do {
+ ret = streaming_ctrl->streaming_read( streaming_ctrl );
+ if( ret<0 && streaming_ctrl->buffer->length<streaming_ctrl->prebuffer_size ) {
+ // Need buffering
+ streaming_ctrl->buffering = 1;
+ }
+ } while( streaming_ctrl->buffer->length>streaming_ctrl->prebuffer_size );
+ } else {
+ if( streaming_ctrl->buffer->length>streaming_ctrl->prebuffer_size ) {
+ streaming_ctrl->buffering = 0;
+ printf("\n");
+ } else {
+ printf(" Buffering: %d \%\r", (int)((float)(((float)streaming_ctrl->buffer->length)/((float)streaming_ctrl->prebuffer_size))*100) );
+ fflush(stdout);
+ }
+ }
+ }
+ } else {
+ printf("Network fd not set\n");
+ }
+ } while( streaming_ctrl->status==streaming_playing_e );
+
+ // Flush the buffer
+ while( streaming_ctrl->buffer->length>0 ) {
+ ret = streaming_ctrl->streaming_read( streaming_ctrl );
+ if( ret<0 ) break;
+ }
+
+printf("Network thread done\n");
+
+ // Close to the pipe to stop mplayer.
+ close( streaming_ctrl->fd_pipe_in );
+
+}
+
+int
+streaming_start(URL_t **url, int fd, int streaming_type) {
+ int fd_pipe[2];
+ // Open the pipe
+ if( pipe(fd_pipe)<0 ) {
+ printf("Pipe creation failed\n");
+ return -1;
+ }
+
+ streaming_ctrl = streaming_ctrl_new( );
+ if( streaming_ctrl==NULL ) {
+ return -1;
+ }
+ streaming_ctrl->url = url;
+ streaming_ctrl->fd_pipe_in = fd_pipe[1];
+ streaming_ctrl->fd_net = fd;
+
+#ifdef DUMP2FILE
+{
+ int fd_file;
+ fd_file = open("dump.stream", O_WRONLY | O_CREAT );
+ if( fd_file<0 ) {
+ perror("open");
+ }
+ streaming_ctrl->fd_pipe_in = fd_file;
+}
+#endif
+
+ switch( streaming_type ) {
+ case DEMUXER_TYPE_ASF:
+ // Send the appropriate HTTP request
+ fd = asf_http_streaming_start( streaming_ctrl );
+ break;
+ case DEMUXER_TYPE_AVI:
+ case DEMUXER_TYPE_MPEG_ES:
+ case DEMUXER_TYPE_MPEG_PS:
+ fd = nop_streaming_start( streaming_ctrl );
+ break;
+ case DEMUXER_TYPE_UNKNOWN:
+ default:
+ printf("Unable to detect the streaming type\n");
+ close( fd );
+ free( streaming_ctrl );
+ return -1;
+ }
+
+ if( fd<0 ) {
+ free( streaming_ctrl );
+ return -1;
+ }
+
+ // Start the network thread
+ if( pthread_create( &(streaming_ctrl->thread_id), NULL , (void*)network_streaming, (void*)NULL)<0 ) {
+ printf("Unable to start the network thread.\n");
+ close( fd );
+ free( streaming_ctrl );
+ return -1;
+ }
+printf("Network thread created with id: %d\n", streaming_ctrl->thread_id );
+
+// streaming_ctrl->status = streaming_stopped_e;
+
+// return fd;
+ return fd_pipe[0];
+}
+
+int
+streaming_stop( ) {
+ streaming_ctrl->status = streaming_stopped_e;
+ return 0;
+}
diff --git a/libmpdemux/network.h b/libmpdemux/network.h
new file mode 100644
index 0000000000..4ef14500e7
--- /dev/null
+++ b/libmpdemux/network.h
@@ -0,0 +1,49 @@
+/*
+ * Network layer for MPlayer
+ * by Bertrand BAUDET <bertrand_baudet@yahoo.com>
+ * (C) 2001, MPlayer team.
+ */
+
+#ifndef __NETWORK_H
+#define __NETWORK_H
+
+#include <pthread.h>
+
+#include "stream.h"
+
+#include "url.h"
+
+#define BUFFER_SIZE 2048
+
+typedef enum {
+ streaming_stopped_e,
+ streaming_playing_e
+} streaming_status;
+
+typedef struct {
+ char *buffer;
+ int length;
+} Net_Fifo;
+
+typedef struct streaming_control {
+ URL_t **url;
+ int fd_net;
+ int fd_pipe_in;
+ streaming_status status;
+ pthread_t thread_id;
+ Net_Fifo *buffer;
+ int buffering; // boolean
+ int prebuffer_size;
+ int (*streaming_read)( struct streaming_control *stream_ctrl );
+} streaming_ctrl_t;
+
+Net_Fifo* net_fifo_new( );
+void net_fifo_free(Net_Fifo *net_fifo );
+int net_fifo_pop(Net_Fifo *net_fifo, char *buffer, int length );
+int net_fifo_push(Net_Fifo *net_fifo, char *buffer, int length );
+
+int connect2Server(char *host, int port);
+int readFromServer(int fd, char *buffer, int length );
+int autodetectProtocol( URL_t *url, int *fd_out );
+
+#endif
diff --git a/libmpdemux/open.c b/libmpdemux/open.c
new file mode 100644
index 0000000000..774e65c32c
--- /dev/null
+++ b/libmpdemux/open.c
@@ -0,0 +1,437 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#ifdef __FreeBSD__
+#include <sys/cdrio.h>
+#endif
+
+#include "stream.h"
+#include "demuxer.h"
+
+#ifdef STREAMING
+#include "url.h"
+#include "network.h"
+static URL_t* url;
+#endif
+
+int dvd_title=0;
+int dvd_chapter=1;
+int dvd_angle=1;
+
+#ifdef USE_DVDREAD
+
+#include <dvdread/dvd_reader.h>
+#include <dvdread/ifo_types.h>
+#include <dvdread/ifo_read.h>
+#include <dvdread/nav_read.h>
+
+#define DVDREAD_VERSION(maj,min,micro) ((maj)*10000 + (min)*100 + (micro))
+
+/*
+ * Try to autodetect the libdvd-0.9.0 library
+ * (0.9.0 removed the <dvdread/dvd_udf.h> header, and moved the two defines
+ * DVD_VIDEO_LB_LEN and MAX_UDF_FILE_NAME_LEN from it to
+ * <dvdread/dvd_reader.h>)
+ */
+#if defined(DVD_VIDEO_LB_LEN) && defined(MAX_UDF_FILE_NAME_LEN)
+#define LIBDVDREAD_VERSION DVDREAD_VERSION(0,9,0)
+#else
+#define LIBDVDREAD_VERSION DVDREAD_VERSION(0,8,0)
+#endif
+
+
+typedef struct {
+ dvd_reader_t *dvd;
+ dvd_file_t *title;
+ ifo_handle_t *vmg_file;
+ tt_srpt_t *tt_srpt;
+ ifo_handle_t *vts_file;
+ vts_ptt_srpt_t *vts_ptt_srpt;
+ pgc_t *cur_pgc;
+ //
+ int cur_cell;
+ int cur_pack;
+ int cell_last_pack;
+ // Navi:
+ int packs_left;
+ dsi_t dsi_pack;
+ int angle_seek;
+} dvd_priv_t;
+
+#endif
+
+extern int vcd_get_track_end(int fd,int track);
+
+// Open a new stream (stdin/file/vcd/url)
+
+stream_t* open_stream(char* filename,int vcd_track,int* file_format){
+stream_t* stream=NULL;
+int f=-1;
+off_t len;
+#ifdef VCD_CACHE
+int vcd_cache_size=128;
+#endif
+#ifdef __FreeBSD__
+int bsize = VCD_SECTOR_SIZE;
+#endif
+
+//============ Open VideoCD track ==============
+if(vcd_track){
+ int ret,ret2;
+ if(!filename) filename=DEFAULT_CDROM_DEVICE;
+ f=open(filename,O_RDONLY);
+ if(f<0){ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CdDevNotfound,filename);return NULL; }
+ vcd_read_toc(f);
+ ret2=vcd_get_track_end(f,vcd_track);
+ if(ret2<0){ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (get)\n");return NULL;}
+ ret=vcd_seek_to_track(f,vcd_track);
+ if(ret<0){ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (seek)\n");return NULL;}
+// seek_to_byte+=ret;
+ mp_msg(MSGT_OPEN,MSGL_V,"VCD start byte position: 0x%X end: 0x%X\n",ret,ret2);
+#ifdef VCD_CACHE
+ vcd_cache_init(vcd_cache_size);
+#endif
+#ifdef __FreeBSD__
+ if (ioctl (f, CDRIOCSETBLOCKSIZE, &bsize) == -1) {
+ perror ( "Error in CDRIOCSETBLOCKSIZE");
+ }
+#endif
+ stream=new_stream(f,STREAMTYPE_VCD);
+ stream->start_pos=ret;
+ stream->end_pos=ret2;
+ return stream;
+}
+
+//============ Open DVD title ==============
+#ifdef USE_DVDREAD
+if(dvd_title){
+// int ret,ret2;
+ dvd_priv_t *d;
+ int ttn,pgc_id,pgn;
+ dvd_reader_t *dvd;
+ dvd_file_t *title;
+ ifo_handle_t *vmg_file;
+ tt_srpt_t *tt_srpt;
+ ifo_handle_t *vts_file;
+ /**
+ * Open the disc.
+ */
+ if(!filename) filename=DEFAULT_DVD_DEVICE;
+ dvd = DVDOpen(filename);
+ if( !dvd ) {
+ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,filename);
+ return NULL;
+ }
+
+ mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_DVDwait);
+
+ /**
+ * Load the video manager to find out the information about the titles on
+ * this disc.
+ */
+ vmg_file = ifoOpen( dvd, 0 );
+ if( !vmg_file ) {
+ mp_msg(MSGT_OPEN,MSGL_ERR, "Can't open VMG info!\n");
+ DVDClose( dvd );
+ return NULL;
+ }
+ tt_srpt = vmg_file->tt_srpt;
+ /**
+ * Make sure our title number is valid.
+ */
+ mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDnumTitles,
+ tt_srpt->nr_of_srpts );
+ if( dvd_title < 1 || dvd_title > tt_srpt->nr_of_srpts ) {
+ mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidTitle, dvd_title);
+ ifoClose( vmg_file );
+ DVDClose( dvd );
+ return NULL;
+ }
+ --dvd_title; // remap 1.. -> 0..
+ /**
+ * Make sure the chapter number is valid for this title.
+ */
+ mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDnumChapters,
+ tt_srpt->title[dvd_title].nr_of_ptts );
+ if( dvd_chapter<1 || dvd_chapter>tt_srpt->title[dvd_title].nr_of_ptts ) {
+ mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidChapter, dvd_chapter);
+ ifoClose( vmg_file );
+ DVDClose( dvd );
+ return NULL;
+ }
+ --dvd_chapter; // remap 1.. -> 0..
+ /**
+ * Make sure the angle number is valid for this title.
+ */
+ mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDnumAngles,
+ tt_srpt->title[dvd_title].nr_of_angles );
+ if( dvd_angle<1 || dvd_angle>tt_srpt->title[dvd_title].nr_of_angles ) {
+ mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidAngle, dvd_angle);
+ ifoClose( vmg_file );
+ DVDClose( dvd );
+ return NULL;
+ }
+ --dvd_angle; // remap 1.. -> 0..
+ /**
+ * Load the VTS information for the title set our title is in.
+ */
+ vts_file = ifoOpen( dvd, tt_srpt->title[dvd_title].title_set_nr );
+ if( !vts_file ) {
+ mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDnoIFO,
+ tt_srpt->title[dvd_title].title_set_nr );
+ ifoClose( vmg_file );
+ DVDClose( dvd );
+ return NULL;
+ }
+ /**
+ * We've got enough info, time to open the title set data.
+ */
+ title = DVDOpenFile( dvd, tt_srpt->title[dvd_title].title_set_nr,
+ DVD_READ_TITLE_VOBS );
+ if( !title ) {
+ mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDnoVOBs,
+ tt_srpt->title[dvd_title].title_set_nr );
+ ifoClose( vts_file );
+ ifoClose( vmg_file );
+ DVDClose( dvd );
+ return NULL;
+ }
+
+ mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDopenOk);
+ // store data
+ d=malloc(sizeof(dvd_priv_t)); memset(d,0,sizeof(dvd_priv_t));
+ d->dvd=dvd;
+ d->title=title;
+ d->vmg_file=vmg_file;
+ d->tt_srpt=tt_srpt;
+ d->vts_file=vts_file;
+
+ /**
+ * Determine which program chain we want to watch. This is based on the
+ * chapter number.
+ */
+ ttn = tt_srpt->title[ dvd_title ].vts_ttn; // local
+ pgc_id = vts_file->vts_ptt_srpt->title[ttn-1].ptt[dvd_chapter].pgcn; // local
+ pgn = vts_file->vts_ptt_srpt->title[ttn-1].ptt[dvd_chapter].pgn; // local
+ d->cur_pgc = vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc;
+ d->cur_cell = d->cur_pgc->program_map[pgn-1] - 1; // start playback here
+ d->packs_left=-1; // for Navi stuff
+ d->angle_seek=0;
+
+ if( d->cur_pgc->cell_playback[d->cur_cell].block_type
+ == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle;
+ d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector;
+ d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector;
+ mp_msg(MSGT_DVD,MSGL_V, "DVD start cell: %d pack: 0x%X-0x%X \n",d->cur_cell,d->cur_pack,d->cell_last_pack);
+
+ // ... (unimplemented)
+// return NULL;
+ stream=new_stream(-1,STREAMTYPE_DVD);
+ stream->start_pos=(off_t)d->cur_pack*2048;
+ //stream->end_pos=0;
+ stream->priv=(void*)d;
+ return stream;
+}
+#endif
+
+//============ Open STDIN ============
+ if(!strcmp(filename,"-")){
+ // read from stdin
+ mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_ReadSTDIN);
+ f=0; // 0=stdin
+ stream=new_stream(f,STREAMTYPE_STREAM);
+ return stream;
+ }
+
+#ifdef STREAMING
+ url = url_new(filename);
+ if(url) {
+ (*file_format)=autodetectProtocol( url, &f );
+ if( (*file_format)==DEMUXER_TYPE_UNKNOWN ) {
+ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_UnableOpenURL, filename);
+ url_free(url);
+ return NULL;
+ }
+ f=streaming_start( &url, f, *file_format );
+ if(f<0){ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_UnableOpenURL, url->url); return NULL; }
+ mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_ConnToServer, url->hostname );
+ stream=new_stream(f,STREAMTYPE_STREAM);
+ return NULL;
+ }
+#endif
+
+//============ Open plain FILE ============
+ f=open(filename,O_RDONLY);
+ if(f<0){ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_FileNotFound,filename);return NULL; }
+ len=lseek(f,0,SEEK_END); lseek(f,0,SEEK_SET);
+ if (len == -1)
+ perror("Error: lseek failed to obtain video file size");
+ else
+ if(verbose)
+#ifdef _LARGEFILE_SOURCE
+ mp_msg(MSGT_OPEN,MSGL_V,"File size is %lld bytes\n", (long long)len);
+#else
+ mp_msg(MSGT_OPEN,MSGL_V,"File size is %u bytes\n", (unsigned int)len);
+#endif
+ stream=new_stream(f,STREAMTYPE_FILE);
+ stream->end_pos=len;
+ return stream;
+
+}
+
+
+#ifdef USE_DVDREAD
+
+static int dvd_next_cell(dvd_priv_t *d){
+ int next_cell=d->cur_cell;
+
+ mp_msg(MSGT_DVD,MSGL_V, "dvd_next_cell: next1=0x%X \n",next_cell);
+
+ if( d->cur_pgc->cell_playback[ next_cell ].block_type
+ == BLOCK_TYPE_ANGLE_BLOCK ) {
+ while(next_cell<d->cur_pgc->nr_of_cells){
+ if( d->cur_pgc->cell_playback[next_cell].block_mode
+ == BLOCK_MODE_LAST_CELL ) break;
+ ++next_cell;
+ }
+ }
+ mp_msg(MSGT_DVD,MSGL_V, "dvd_next_cell: next2=0x%X \n",next_cell);
+
+ ++next_cell;
+ if(next_cell>=d->cur_pgc->nr_of_cells) return -1; // EOF
+ if( d->cur_pgc->cell_playback[next_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ){
+ next_cell+=dvd_angle;
+ if(next_cell>=d->cur_pgc->nr_of_cells) return -1; // EOF
+ }
+ mp_msg(MSGT_DVD,MSGL_V, "dvd_next_cell: next3=0x%X \n",next_cell);
+ return next_cell;
+}
+
+int dvd_read_sector(dvd_priv_t *d,unsigned char* data){
+ int len;
+
+ if(d->packs_left==0){
+ /**
+ * If we're not at the end of this cell, we can determine the next
+ * VOBU to display using the VOBU_SRI information section of the
+ * DSI. Using this value correctly follows the current angle,
+ * avoiding the doubled scenes in The Matrix, and makes our life
+ * really happy.
+ *
+ * Otherwise, we set our next address past the end of this cell to
+ * force the code above to go to the next cell in the program.
+ */
+ if( d->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL ) {
+ d->cur_pack= d->dsi_pack.dsi_gi.nv_pck_lbn +
+ ( d->dsi_pack.vobu_sri.next_vobu & 0x7fffffff );
+ mp_msg(MSGT_DVD,MSGL_DBG2, "Navi new pos=0x%X \n",d->cur_pack);
+ } else {
+ // end of cell! find next cell!
+ mp_msg(MSGT_DVD,MSGL_V, "--- END OF CELL !!! ---\n");
+ d->cur_pack=d->cell_last_pack+1;
+ }
+ }
+
+read_next:
+
+ if(d->cur_pack>d->cell_last_pack){
+ // end of cell!
+ int next=dvd_next_cell(d);
+ if(next>=0){
+ d->cur_cell=next;
+
+// if( d->cur_pgc->cell_playback[d->cur_cell].block_type
+// == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle;
+ d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector;
+ d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector;
+ mp_msg(MSGT_DVD,MSGL_V, "DVD next cell: %d pack: 0x%X-0x%X \n",d->cur_cell,d->cur_pack,d->cell_last_pack);
+
+ } else return -1; // EOF
+ }
+
+ len = DVDReadBlocks( d->title, d->cur_pack, 1, data );
+ if(!len) return -1; //error
+
+ if(data[38]==0 && data[39]==0 && data[40]==1 && data[41]==0xBF &&
+ data[1024]==0 && data[1025]==0 && data[1026]==1 && data[1027]==0xBF){
+ // found a Navi packet!!!
+#if LIBDVDREAD_VERSION >= DVDREAD_VERSION(0,9,0)
+ navRead_DSI( &d->dsi_pack, &(data[ DSI_START_BYTE ]) );
+#else
+ navRead_DSI( &d->dsi_pack, &(data[ DSI_START_BYTE ]), sizeof(dsi_t) );
+#endif
+ if(d->cur_pack != d->dsi_pack.dsi_gi.nv_pck_lbn ){
+ mp_msg(MSGT_DVD,MSGL_V, "Invalid NAVI packet! lba=0x%X navi=0x%X \n",
+ d->cur_pack,d->dsi_pack.dsi_gi.nv_pck_lbn);
+ } else {
+ // process!
+ d->packs_left = d->dsi_pack.dsi_gi.vobu_ea;
+ mp_msg(MSGT_DVD,MSGL_DBG2, "Found NAVI packet! lba=0x%X len=%d \n",d->cur_pack,d->packs_left);
+ if(d->angle_seek){
+ int skip=d->dsi_pack.sml_agli.data[dvd_angle].address;
+ if(skip) d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+skip;
+ d->angle_seek=0;
+ mp_msg(MSGT_DVD,MSGL_V, "Angle-seek synced! skip=%d new_lba=0x%X \n",skip,d->cur_pack);
+ }
+ }
+ ++d->cur_pack;
+ goto read_next;
+ }
+
+ ++d->cur_pack;
+ if(d->packs_left>=0) --d->packs_left;
+
+ if(d->angle_seek) goto read_next; // searching for Navi packet
+
+ return d->cur_pack-1;
+}
+
+void dvd_seek(dvd_priv_t *d,int pos){
+ d->packs_left=-1;
+ d->cur_pack=pos;
+
+// check if we stay in current cell (speedup things, and avoid angle skip)
+if(d->cur_pack>d->cell_last_pack ||
+ d->cur_pack<d->cur_pgc->cell_playback[ d->cur_cell ].first_sector){
+
+ // ok, cell change, find the right cell!
+ d->cur_cell=0;
+ if( d->cur_pgc->cell_playback[d->cur_cell].block_type
+ == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle;
+
+ while(1){
+ int next;
+ d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector;
+ if(d->cur_pack<d->cur_pgc->cell_playback[ d->cur_cell ].first_sector){
+ d->cur_pack=d->cur_pgc->cell_playback[ d->cur_cell ].first_sector;
+ break;
+ }
+ if(d->cur_pack<=d->cell_last_pack) break; // ok, we find it! :)
+ next=dvd_next_cell(d);
+ if(next<0){
+// d->cur_pack=d->cell_last_pack+1;
+ break; // we're after the last cell
+ }
+ d->cur_cell=next;
+ }
+
+}
+
+mp_msg(MSGT_DVD,MSGL_V, "DVD Seek! lba=0x%X cell=%d packs: 0x%X-0x%X \n",
+ d->cur_pack,d->cur_cell,d->cur_pgc->cell_playback[ d->cur_cell ].first_sector,d->cell_last_pack);
+
+// if we're in interleaved multi-angle cell, find the right angle chain!
+// (read Navi block, and use the seamless angle jump table)
+d->angle_seek=1;
+
+}
+
+#endif
diff --git a/libmpdemux/parse_es.c b/libmpdemux/parse_es.c
new file mode 100644
index 0000000000..310b1c976d
--- /dev/null
+++ b/libmpdemux/parse_es.c
@@ -0,0 +1,117 @@
+//=================== MPEG-ES VIDEO PARSER =========================
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern int verbose; // defined in mplayer.c
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "stream.h"
+#include "demuxer.h"
+
+#include "parse_es.h"
+
+//static unsigned char videobuffer[MAX_VIDEO_PACKET_SIZE];
+unsigned char* videobuffer=NULL;
+int videobuf_len=0;
+unsigned char videobuf_code[4];
+int videobuf_code_len=0;
+
+// sync video stream, and returns next packet code
+int sync_video_packet(demux_stream_t *ds){
+ int skipped=0;
+ // we need enough bytes in the buffer:
+ while(videobuf_code_len<4){
+#if 0
+ int c;
+ c=demux_getc(ds);if(c<0){ return 0;} // EOF
+ videobuf_code[videobuf_code_len++]=c;
+#else
+ videobuf_code[videobuf_code_len++]=demux_getc(ds);
+#endif
+ }
+ // sync packet:
+ while(1){
+ int c;
+ if(videobuf_code[0]==0 &&
+ videobuf_code[1]==0 &&
+ videobuf_code[2]==1) break; // synced
+ // shift buffer, drop first byte
+ ++skipped;
+ videobuf_code[0]=videobuf_code[1];
+ videobuf_code[1]=videobuf_code[2];
+ videobuf_code[2]=videobuf_code[3];
+ c=demux_getc(ds);if(c<0){ return 0;} // EOF
+ videobuf_code[3]=c;
+ }
+ if(skipped) mp_dbg(MSGT_PARSEES,MSGL_DBG2,"videobuf: %d bytes skipped (next: 0x1%02X)\n",skipped,videobuf_code[3]);
+ return 0x100|videobuf_code[3];
+}
+
+// return: packet length
+int read_video_packet(demux_stream_t *ds){
+int packet_start;
+
+ // SYNC STREAM
+// if(!sync_video_packet(ds)) return 0; // cannot sync (EOF)
+
+ // COPY STARTCODE:
+ packet_start=videobuf_len;
+ videobuffer[videobuf_len+0]=videobuf_code[0];
+ videobuffer[videobuf_len+1]=videobuf_code[1];
+ videobuffer[videobuf_len+2]=videobuf_code[2];
+ videobuffer[videobuf_len+3]=videobuf_code[3];
+ videobuf_len+=4;
+
+ // READ PACKET:
+ { unsigned int head=-1;
+ while(videobuf_len<VIDEOBUFFER_SIZE){
+ int c=demux_getc(ds);
+ if(c<0) break; // EOF
+ videobuffer[videobuf_len++]=c;
+#if 1
+ head<<=8;
+ if(head==0x100) break; // synced
+ head|=c;
+#else
+ if(videobuffer[videobuf_len-4]==0 &&
+ videobuffer[videobuf_len-3]==0 &&
+ videobuffer[videobuf_len-2]==1) break; // synced
+#endif
+ }
+ }
+
+ if(ds->eof){
+ videobuf_code_len=0; // EOF, no next code
+ return videobuf_len-packet_start;
+ }
+
+ videobuf_len-=4;
+
+ mp_dbg(MSGT_PARSEES,MSGL_DBG2,"videobuf: packet 0x1%02X len=%d (total=%d)\n",videobuffer[packet_start+3],videobuf_len-packet_start,videobuf_len);
+
+ // Save next packet code:
+ videobuf_code[0]=videobuffer[videobuf_len];
+ videobuf_code[1]=videobuffer[videobuf_len+1];
+ videobuf_code[2]=videobuffer[videobuf_len+2];
+ videobuf_code[3]=videobuffer[videobuf_len+3];
+ videobuf_code_len=4;
+
+ return videobuf_len-packet_start;
+}
+
+// return: next packet code
+int skip_video_packet(demux_stream_t *ds){
+
+ // SYNC STREAM
+// if(!sync_video_packet(ds)) return 0; // cannot sync (EOF)
+
+ videobuf_code_len=0; // force resync
+
+ // SYNC AGAIN:
+ return sync_video_packet(ds);
+}
diff --git a/libmpdemux/parse_es.h b/libmpdemux/parse_es.h
new file mode 100644
index 0000000000..45936b396a
--- /dev/null
+++ b/libmpdemux/parse_es.h
@@ -0,0 +1,18 @@
+
+#define MAX_VIDEO_PACKET_SIZE (224*1024+4)
+#define VIDEOBUFFER_SIZE 0x100000
+
+extern unsigned char* videobuffer;
+extern int videobuf_len;
+extern unsigned char videobuf_code[4];
+extern int videobuf_code_len;
+
+// sync video stream, and returns next packet code
+int sync_video_packet(demux_stream_t *ds);
+
+// return: packet length
+int read_video_packet(demux_stream_t *ds);
+
+// return: next packet code
+int skip_video_packet(demux_stream_t *ds);
+
diff --git a/libmpdemux/stheader.h b/libmpdemux/stheader.h
new file mode 100644
index 0000000000..0e83c53d84
--- /dev/null
+++ b/libmpdemux/stheader.h
@@ -0,0 +1,94 @@
+// Stream headers:
+
+/*
+typedef struct {
+ int driver;
+ // codec descriptor from codec.conf
+} codecinfo_t;
+*/
+
+#ifdef HAVE_OGGVORBIS
+#include <math.h>
+#include <vorbis/codec.h>
+typedef struct {
+ ogg_sync_state oy; /* sync and verify incoming physical bitstream */
+ ogg_stream_state os; /* take physical pages, weld into a logical
+ stream of packets */
+ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
+ ogg_packet op; /* one raw packet of data for decode */
+
+ vorbis_info vi; /* struct that stores all the static vorbis bitstream
+ settings */
+ vorbis_comment vc; /* struct that stores all the bitstream user comments */
+ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
+ vorbis_block vb; /* local working space for packet->PCM decode */
+} ov_struct_t;
+#endif
+
+typedef struct {
+ demux_stream_t *ds;
+ unsigned int format;
+ struct codecs_st *codec;
+ int inited;
+ // output format:
+ float timer; // value of old a_frame
+ int samplerate;
+ int samplesize;
+ int channels;
+ int o_bps; // == samplerate*samplesize*channels (uncompr. bytes/sec)
+ int i_bps; // == bitrate (compressed bytes/sec)
+ // in buffers:
+ char* a_in_buffer;
+ int a_in_buffer_len;
+ int a_in_buffer_size;
+ // out buffers:
+ char* a_buffer;
+ int a_buffer_len;
+ int a_buffer_size;
+ int sample_format;
+ // win32 codec stuff:
+ AVIStreamHeader audio;
+ WAVEFORMATEX *wf;
+// char wf_ext[64]; // in format
+ WAVEFORMATEX o_wf; // out format
+ HACMSTREAM srcstream; // handle
+ int audio_in_minsize;
+ int audio_out_minsize;
+ // other codecs:
+// ac3_frame_t *ac3_frame;
+ void* ac3_frame;
+ int pcm_bswap;
+#ifdef HAVE_OGGVORBIS
+ ov_struct_t *ov; // should be assigned on init
+#endif
+} sh_audio_t;
+
+typedef struct {
+ demux_stream_t *ds;
+ unsigned int format;
+ struct codecs_st *codec;
+ int inited;
+ // output format:
+ float timer; // value of old v_frame
+ float fps;
+ float frametime; // 1/fps
+ int i_bps; // == bitrate (compressed bytes/sec)
+ int disp_w,disp_h; // display size (filled by fileformat parser)
+// int coded_w,coded_h; // coded size (filled by video codec)
+ float aspect;
+ unsigned int outfmtidx;
+// unsigned int bitrate;
+ // buffers:
+ float num_frames; // number of frames played
+ int num_frames_decoded; // number of frames decoded
+ char *our_out_buffer;
+ // win32 codec stuff:
+ AVIStreamHeader video;
+ BITMAPINFOHEADER *bih; // in format
+ BITMAPINFOHEADER o_bih; // out format
+ HIC hic; // handle
+} sh_video_t;
+
+sh_audio_t* new_sh_audio(demuxer_t *demuxer,int id);
+sh_video_t* new_sh_video(demuxer_t *demuxer,int id);
+
diff --git a/libmpdemux/stream.c b/libmpdemux/stream.c
new file mode 100644
index 0000000000..de138cef02
--- /dev/null
+++ b/libmpdemux/stream.c
@@ -0,0 +1,188 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "stream.h"
+
+extern int verbose; // defined in mplayer.c
+
+#ifdef __FreeBSD__
+#include "vcd_read_fbsd.h"
+#else
+#include "vcd_read.h"
+#endif
+
+#ifdef USE_DVDREAD
+int dvd_read_sector(void* d,void* p2);
+void dvd_seek(void* d,off_t pos);
+#endif
+
+//=================== STREAMER =========================
+
+int stream_fill_buffer(stream_t *s){
+ int len;
+ if(s->eof){ s->buf_pos=s->buf_len=0; return 0; }
+ switch(s->type){
+ case STREAMTYPE_FILE:
+ case STREAMTYPE_STREAM:
+ len=read(s->fd,s->buffer,STREAM_BUFFER_SIZE);break;
+ case STREAMTYPE_VCD:
+#ifdef VCD_CACHE
+ len=vcd_cache_read(s->fd,s->buffer);break;
+#else
+ len=vcd_read(s->fd,s->buffer);break;
+#endif
+#ifdef USE_DVDREAD
+ case STREAMTYPE_DVD: {
+ off_t pos=dvd_read_sector(s->priv,s->buffer);
+ if(pos>=0){
+ len=2048; // full sector
+ s->pos=2048*pos-len;
+ } else len=-1; // error
+ break;
+ }
+#endif
+ default: len=0;
+ }
+ if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; return 0; }
+ s->buf_pos=0;
+ s->buf_len=len;
+ s->pos+=len;
+// printf("[%d]",len);fflush(stdout);
+ return len;
+}
+
+int stream_seek_long(stream_t *s,off_t pos){
+off_t newpos;
+
+// if(verbose>=3) printf("seek_long to 0x%X\n",(unsigned int)pos);
+
+ s->buf_pos=s->buf_len=0;
+
+ switch(s->type){
+ case STREAMTYPE_FILE:
+ case STREAMTYPE_STREAM:
+#ifdef _LARGEFILE_SOURCE
+ newpos=pos&(~((long long)STREAM_BUFFER_SIZE-1));break;
+#else
+ newpos=pos&(~(STREAM_BUFFER_SIZE-1));break;
+#endif
+ case STREAMTYPE_VCD:
+ newpos=(pos/VCD_SECTOR_DATA)*VCD_SECTOR_DATA;break;
+ case STREAMTYPE_DVD:
+ newpos=pos/2048; newpos*=2048; break;
+ }
+
+if(verbose>=3){
+#ifdef _LARGEFILE_SOURCE
+ printf("s->pos=%llX newpos=%llX new_bufpos=%llX buflen=%X \n",
+ (long long)s->pos,(long long)newpos,(long long)pos,s->buf_len);
+#else
+ printf("s->pos=%X newpos=%X new_bufpos=%X buflen=%X \n",
+ (unsigned int)s->pos,newpos,pos,s->buf_len);
+#endif
+}
+
+ pos-=newpos;
+
+if(newpos==0 || newpos!=s->pos){
+ switch(s->type){
+ case STREAMTYPE_FILE:
+ s->pos=newpos; // real seek
+ if(lseek(s->fd,s->pos,SEEK_SET)<0) s->eof=1;
+ break;
+ case STREAMTYPE_VCD:
+ s->pos=newpos; // real seek
+#ifdef VCD_CACHE
+ vcd_cache_seek(s->pos/VCD_SECTOR_DATA);
+#else
+ vcd_set_msf(s->pos/VCD_SECTOR_DATA);
+#endif
+ break;
+#ifdef USE_DVDREAD
+ case STREAMTYPE_DVD:
+ s->pos=newpos; // real seek
+ dvd_seek(s->priv,s->pos/2048);
+ break;
+#endif
+ case STREAMTYPE_STREAM:
+ //s->pos=newpos; // real seek
+ if(newpos<s->pos){
+ mp_msg(MSGT_STREAM,MSGL_INFO,"Cannot seek backward in linear streams!\n");
+ return 1;
+ }
+ while(s->pos<newpos){
+ if(stream_fill_buffer(s)<=0) break; // EOF
+ }
+ break;
+ }
+// putchar('.');fflush(stdout);
+//} else {
+// putchar('%');fflush(stdout);
+}
+
+ stream_fill_buffer(s);
+ if(pos>=0 && pos<=s->buf_len){
+ s->buf_pos=pos; // byte position in sector
+ return 1;
+ }
+
+// if(pos==s->buf_len) printf("XXX Seek to last byte of file -> EOF\n");
+
+#ifdef _LARGEFILE_SOURCE
+ mp_msg(MSGT_STREAM,MSGL_V,"stream_seek: WARNING! Can't seek to 0x%llX !\n",(long long)(pos+newpos));
+#else
+ mp_msg(MSGT_STREAM,MSGL_V,"stream_seek: WARNING! Can't seek to 0x%X !\n",(pos+newpos));
+#endif
+ return 0;
+}
+
+
+void stream_reset(stream_t *s){
+ if(s->eof){
+ s->pos=0; //ftell(f);
+// s->buf_pos=s->buf_len=0;
+ s->eof=0;
+ }
+ //stream_seek(s,0);
+}
+
+stream_t* new_memory_stream(unsigned char* data,int len){
+ stream_t *s=malloc(sizeof(stream_t)+len);
+ s->fd=-1;
+ s->type=STREAMTYPE_MEMORY;
+ s->buf_pos=0; s->buf_len=len;
+ s->start_pos=0; s->end_pos=len;
+ stream_reset(s);
+ s->pos=len;
+ memcpy(s->buffer,data,len);
+ return s;
+}
+
+stream_t* new_stream(int fd,int type){
+ stream_t *s=malloc(sizeof(stream_t));
+ s->fd=fd;
+ s->type=type;
+ s->buf_pos=s->buf_len=0;
+ s->start_pos=s->end_pos=0;
+ s->priv=NULL;
+ stream_reset(s);
+ return s;
+}
+
+void free_stream(stream_t *s){
+ if(s->priv) free(s->priv);
+ free(s);
+}
+
+
diff --git a/libmpdemux/stream.h b/libmpdemux/stream.h
new file mode 100644
index 0000000000..2859b68bc4
--- /dev/null
+++ b/libmpdemux/stream.h
@@ -0,0 +1,141 @@
+#ifndef __STREAM_H
+#define __STREAM_H
+
+#define STREAM_BUFFER_SIZE 2048
+
+#define STREAMTYPE_FILE 0
+#define STREAMTYPE_VCD 1
+#define STREAMTYPE_STREAM 2 // same as FILE but no seeking (for stdin)
+#define STREAMTYPE_DVD 3
+#define STREAMTYPE_MEMORY 4
+
+#define VCD_SECTOR_SIZE 2352
+#define VCD_SECTOR_OFFS 24
+#define VCD_SECTOR_DATA 2324
+
+int vcd_seek_to_track(int fd,int track);
+void vcd_read_toc(int fd);
+
+#ifdef VCD_CACHE
+void vcd_cache_init(int s);
+#endif
+
+typedef struct {
+ int fd;
+ off_t pos;
+ int eof;
+ int type; // 0=file 1=VCD
+ unsigned int buf_pos,buf_len;
+ off_t start_pos,end_pos;
+ void* priv; // used for DVD
+ unsigned char buffer[STREAM_BUFFER_SIZE>VCD_SECTOR_SIZE?STREAM_BUFFER_SIZE:VCD_SECTOR_SIZE];
+} stream_t;
+
+int stream_fill_buffer(stream_t *s);
+
+int stream_seek_long(stream_t *s,off_t pos);
+
+inline static int stream_read_char(stream_t *s){
+ return (s->buf_pos<s->buf_len)?s->buffer[s->buf_pos++]:
+ (stream_fill_buffer(s)?s->buffer[s->buf_pos++]:-256);
+// if(s->buf_pos<s->buf_len) return s->buffer[s->buf_pos++];
+// stream_fill_buffer(s);
+// if(s->buf_pos<s->buf_len) return s->buffer[s->buf_pos++];
+// return 0; // EOF
+}
+
+inline static unsigned int stream_read_word(stream_t *s){
+ int x,y;
+ x=stream_read_char(s);
+ y=stream_read_char(s);
+ return (x<<8)|y;
+}
+
+inline static unsigned int stream_read_dword(stream_t *s){
+ unsigned int y;
+ y=stream_read_char(s);
+ y=(y<<8)|stream_read_char(s);
+ y=(y<<8)|stream_read_char(s);
+ y=(y<<8)|stream_read_char(s);
+ return y;
+}
+
+inline static unsigned int stream_read_word_le(stream_t *s){
+ int x,y;
+ x=stream_read_char(s);
+ y=stream_read_char(s);
+ return (y<<8)|x;
+}
+
+inline static unsigned int stream_read_dword_le(stream_t *s){
+ unsigned int y;
+ y=stream_read_char(s);
+ y|=stream_read_char(s)<<8;
+ y|=stream_read_char(s)<<16;
+ y|=stream_read_char(s)<<24;
+ return y;
+}
+
+inline static void stream_read(stream_t *s,char* mem,int len){
+ while(len>0){
+ int x;
+ x=s->buf_len-s->buf_pos;
+ if(x==0){
+ if(!stream_fill_buffer(s)) return; // EOF
+ x=s->buf_len-s->buf_pos;
+ }
+ if(s->buf_pos>s->buf_len) printf("stream_read: WARNING! s->buf_pos>s->buf_len\n");
+ if(x>len) x=len;
+ memcpy(mem,&s->buffer[s->buf_pos],x);
+ s->buf_pos+=x; mem+=x; len-=x;
+ }
+}
+
+inline static int stream_eof(stream_t *s){
+ return s->eof;
+}
+
+inline static off_t stream_tell(stream_t *s){
+ return s->pos+s->buf_pos-s->buf_len;
+}
+
+inline static int stream_seek(stream_t *s,off_t pos){
+
+// if(verbose>=3) printf("seek to 0x%qX\n",(long long)pos);
+
+ if(pos<s->pos){
+ off_t x=pos-(s->pos-s->buf_len);
+ if(x>=0){
+ s->buf_pos=x;
+// putchar('*');fflush(stdout);
+ return 1;
+ }
+ }
+
+ return stream_seek_long(s,pos);
+}
+
+inline static int stream_skip(stream_t *s,int len){
+ if(len<0 || (len>2*STREAM_BUFFER_SIZE && s->type!=STREAMTYPE_STREAM)){
+ // negative or big skip!
+ return stream_seek(s,stream_tell(s)+len);
+ }
+ while(len>0){
+ int x=s->buf_len-s->buf_pos;
+ if(x==0){
+ if(!stream_fill_buffer(s)) return 0; // EOF
+ x=s->buf_len-s->buf_pos;
+ }
+ if(x>len) x=len;
+ //memcpy(mem,&s->buf[s->buf_pos],x);
+ s->buf_pos+=x; len-=x;
+ }
+ return 1;
+}
+
+void stream_reset(stream_t *s);
+stream_t* new_stream(int fd,int type);
+void free_stream(stream_t *s);
+stream_t* new_memory_stream(unsigned char* data,int len);
+
+#endif // __STREAM_H
diff --git a/libmpdemux/test.c b/libmpdemux/test.c
new file mode 100644
index 0000000000..ce59b19228
--- /dev/null
+++ b/libmpdemux/test.c
@@ -0,0 +1,66 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mp_msg.h"
+
+#include "stream.h"
+#include "demuxer.h"
+
+#include "wine/mmreg.h"
+#include "wine/avifmt.h"
+#include "wine/vfw.h"
+#include "codec-cfg.h"
+#include "stheader.h"
+
+//--------------------------
+
+// audio stream skip/resync functions requires only for seeking.
+// (they should be implemented in the audio codec layer)
+void skip_audio_frame(sh_audio_t *sh_audio){
+}
+void resync_audio_stream(sh_audio_t *sh_audio){
+}
+
+// some globals:
+int verbose=1;
+
+// AVI demuxer parameters:
+int index_mode=-1; // -1=untouched 0=don't use index 1=use (geneate) index
+int force_ni=0; // force non-interleaved AVI parsing
+int pts_from_bps=1; // PTS: 0=interleaved 1=BPS-based
+
+//---------------
+
+extern stream_t* open_stream(char* filename,int vcd_track,int* file_format);
+
+int main(int argc,char* argv[]){
+
+stream_t* stream=NULL;
+demuxer_t* demuxer=NULL;
+int file_format=DEMUXER_TYPE_UNKNOWN;
+
+ mp_msg_init(verbose+MSGL_STATUS);
+
+ if(argc>1)
+ stream=open_stream(argv[1],0,&file_format);
+ else
+// stream=open_stream("/3d/divx/405divx_sm_v2[1].avi",0,&file_format);
+ stream=open_stream("/dev/cdrom",2,&file_format); // VCD track 2
+
+ if(!stream){
+ printf("Cannot open file/device\n");
+ exit(1);
+ }
+
+ printf("success: format: %d data: 0x%X - 0x%X\n",file_format, (int)(stream->start_pos),(int)(stream->end_pos));
+
+ demuxer=demux_open(stream,file_format,-1,-1,-1);
+ if(!demuxer){
+ printf("Cannot open demuxer\n");
+ exit(1);
+ }
+
+
+}
diff --git a/libmpdemux/url.c b/libmpdemux/url.c
new file mode 100644
index 0000000000..f4a506ec72
--- /dev/null
+++ b/libmpdemux/url.c
@@ -0,0 +1,117 @@
+/*
+ * URL Helper
+ * by Bertrand Baudet <bertrand_baudet@yahoo.com>
+ * (C) 2001, MPlayer team.
+ *
+ * TODO:
+ * Extract the username/password if present
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "url.h"
+
+URL_t*
+url_new(char* url) {
+ int pos1, pos2;
+ URL_t* Curl;
+ char *ptr1, *ptr2;
+
+ // Create the URL container
+ Curl = (URL_t*)malloc(sizeof(URL_t));
+ if( Curl==NULL ) {
+ printf("Memory allocation failed!\n");
+ return NULL;
+ }
+ // Initialisation of the URL container members
+ memset( Curl, 0, sizeof(URL_t) );
+
+ // Copy the url in the URL container
+ Curl->url = (char*)malloc(strlen(url)+1);
+ if( Curl->url==NULL ) {
+ printf("Memory allocation failed!\n");
+ return NULL;
+ }
+ strcpy(Curl->url, url);
+
+ // extract the protocol
+ ptr1 = strstr(url, "://");
+ if( ptr1==NULL ) {
+ printf("Not an URL!\n");
+ return NULL;
+ }
+ pos1 = ptr1-url;
+ Curl->protocol = (char*)malloc(pos1+1);
+ strncpy(Curl->protocol, url, pos1);
+ Curl->protocol[pos1] = '\0';
+
+ // look if the port is given
+ ptr2 = strstr(ptr1+3, ":");
+ if( ptr2==NULL ) {
+ // No port is given
+ // Look if a path is given
+ ptr2 = strstr(ptr1+3, "/");
+ if( ptr2==NULL ) {
+ // No path/filename
+ // So we have an URL like http://www.hostname.com
+ pos2 = strlen(url);
+ } else {
+ // We have an URL like http://www.hostname.com/file.txt
+ pos2 = ptr2-url;
+ }
+ } else {
+ // We have an URL beginning like http://www.hostname.com:1212
+ // Get the port number
+ Curl->port = atoi(ptr2+1);
+ pos2 = ptr2-url;
+ }
+ // copy the hostname in the URL container
+ Curl->hostname = (char*)malloc(pos2-pos1-3+1);
+ if( Curl->hostname==NULL ) {
+ printf("Memory allocation failed!\n");
+ return NULL;
+ }
+ strncpy(Curl->hostname, ptr1+3, pos2-pos1-3);
+ Curl->hostname[pos2-pos1-3] = '\0';
+
+ // Look if a path is given
+ ptr2 = strstr(ptr1+3, "/");
+ if( ptr2!=NULL ) {
+ // A path/filename is given
+ // check if it's not a trailing '/'
+ if( strlen(ptr2)>1 ) {
+ // copy the path/filename in the URL container
+ Curl->file = (char*)malloc(strlen(ptr2)+1);
+ if( Curl->file==NULL ) {
+ printf("Memory allocation failed!\n");
+ return NULL;
+ }
+ strcpy(Curl->file, ptr2);
+ }
+ }
+ // Check if a filenme was given or set, else set it with '/'
+ if( Curl->file==NULL ) {
+ Curl->file = (char*)malloc(2);
+ if( Curl->file==NULL ) {
+ printf("Memory allocation failed!\n");
+ return NULL;
+ }
+ strcpy(Curl->file, "/");
+ }
+
+ return Curl;
+}
+
+void
+url_free(URL_t* url) {
+ if(!url) return;
+ if(url->url) free(url->url);
+ if(url->protocol) free(url->protocol);
+ if(url->hostname) free(url->hostname);
+ if(url->file) free(url->file);
+ if(url->username) free(url->username);
+ if(url->password) free(url->password);
+ free(url);
+}
diff --git a/libmpdemux/url.h b/libmpdemux/url.h
new file mode 100644
index 0000000000..5855296c38
--- /dev/null
+++ b/libmpdemux/url.h
@@ -0,0 +1,23 @@
+/*
+ * URL Helper
+ * by Bertrand Baudet <bertrand_baudet@yahoo.com>
+ * (C) 2001, MPlayer team.
+ */
+
+#ifndef __URL_H
+#define __URL_H
+
+typedef struct {
+ char *url;
+ char *protocol;
+ char *hostname;
+ char *file;
+ unsigned int port;
+ char *username;
+ char *password;
+} URL_t;
+
+URL_t* url_new(char* url);
+void url_free(URL_t* url);
+
+#endif
diff --git a/libmpdemux/vcd_read.h b/libmpdemux/vcd_read.h
new file mode 100644
index 0000000000..9d6564be7a
--- /dev/null
+++ b/libmpdemux/vcd_read.h
@@ -0,0 +1,280 @@
+//=================== VideoCD ==========================
+#if defined(linux) || defined(sun) || defined(__bsdi__)
+
+#if defined(linux)
+#include <linux/cdrom.h>
+#elif defined(sun)
+#include <sys/cdio.h>
+static int sun_vcd_read(int, int*);
+#elif defined(__bsdi__)
+#include <dvd.h>
+#endif
+
+
+static struct cdrom_tocentry vcd_entry;
+
+static inline void vcd_set_msf(unsigned int sect){
+ vcd_entry.cdte_addr.msf.frame=sect%75;
+ sect=sect/75;
+ vcd_entry.cdte_addr.msf.second=sect%60;
+ sect=sect/60;
+ vcd_entry.cdte_addr.msf.minute=sect;
+}
+
+static inline unsigned int vcd_get_msf(){
+ return vcd_entry.cdte_addr.msf.frame +
+ (vcd_entry.cdte_addr.msf.second+
+ vcd_entry.cdte_addr.msf.minute*60)*75;
+}
+
+int vcd_seek_to_track(int fd,int track){
+ vcd_entry.cdte_format = CDROM_MSF;
+ vcd_entry.cdte_track = track;
+ if (ioctl(fd, CDROMREADTOCENTRY, &vcd_entry)) {
+ perror("ioctl dif1");
+ return -1;
+ }
+ return VCD_SECTOR_DATA*vcd_get_msf();
+}
+
+int vcd_get_track_end(int fd,int track){
+ struct cdrom_tochdr tochdr;
+ if (ioctl(fd,CDROMREADTOCHDR,&tochdr)==-1)
+ { perror("read CDROM toc header: "); return -1; }
+ vcd_entry.cdte_format = CDROM_MSF;
+ vcd_entry.cdte_track = track<tochdr.cdth_trk1?(track+1):CDROM_LEADOUT;
+ if (ioctl(fd, CDROMREADTOCENTRY, &vcd_entry)) {
+ perror("ioctl dif2");
+ return -1;
+ }
+ return VCD_SECTOR_DATA*vcd_get_msf();
+}
+
+void vcd_read_toc(int fd){
+ struct cdrom_tochdr tochdr;
+ int i;
+ if (ioctl(fd,CDROMREADTOCHDR,&tochdr)==-1)
+ { perror("read CDROM toc header: "); return; }
+ for (i=tochdr.cdth_trk0 ; i<=tochdr.cdth_trk1 ; i++){
+ struct cdrom_tocentry tocentry;
+
+ tocentry.cdte_track = i;
+ tocentry.cdte_format = CDROM_MSF;
+
+ if (ioctl(fd,CDROMREADTOCENTRY,&tocentry)==-1)
+ { perror("read CDROM toc entry: "); return; }
+
+ mp_msg(MSGT_OPEN,MSGL_INFO,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d mode: %d\n",
+ (int)tocentry.cdte_track,
+ (int)tocentry.cdte_adr,
+ (int)tocentry.cdte_ctrl,
+ (int)tocentry.cdte_format,
+ (int)tocentry.cdte_addr.msf.minute,
+ (int)tocentry.cdte_addr.msf.second,
+ (int)tocentry.cdte_addr.msf.frame,
+ (int)tocentry.cdte_datamode
+ );
+ }
+}
+
+
+static char vcd_buf[VCD_SECTOR_SIZE];
+
+static int vcd_read(int fd,char *mem){
+#if defined(linux) || defined(__bsdi__)
+ memcpy(vcd_buf,&vcd_entry.cdte_addr.msf,sizeof(struct cdrom_msf));
+ if(ioctl(fd,CDROMREADRAW,vcd_buf)==-1) return 0; // EOF?
+ memcpy(mem,&vcd_buf[VCD_SECTOR_OFFS],VCD_SECTOR_DATA);
+#elif defined(sun)
+ {
+ int offset;
+ if (sun_vcd_read(fd, &offset) <= 0) return 0;
+ memcpy(mem,&vcd_buf[offset],VCD_SECTOR_DATA);
+ }
+#endif
+
+ vcd_entry.cdte_addr.msf.frame++;
+ if (vcd_entry.cdte_addr.msf.frame==75){
+ vcd_entry.cdte_addr.msf.frame=0;
+ vcd_entry.cdte_addr.msf.second++;
+ if (vcd_entry.cdte_addr.msf.second==60){
+ vcd_entry.cdte_addr.msf.second=0;
+ vcd_entry.cdte_addr.msf.minute++;
+ }
+ }
+
+ return VCD_SECTOR_DATA;
+}
+
+
+#ifdef sun
+#include <sys/scsi/generic/commands.h>
+#include <sys/scsi/impl/uscsi.h>
+
+#define SUN_XAREAD 1 /*fails on atapi drives*/
+#define SUN_MODE2READ 2 /*fails on atapi drives*/
+#define SUN_SCSIREAD 3
+#define SUN_VCDREAD SUN_SCSIREAD
+
+static int sun_vcd_read(int fd, int *offset)
+{
+#if SUN_VCDREAD == SUN_XAREAD
+ struct cdrom_cdxa cdxa;
+ cdxa.cdxa_addr = vcd_get_msf();
+ cdxa.cdxa_length = 1;
+ cdxa.cdxa_data = vcd_buf;
+ cdxa.cdxa_format = CDROM_XA_SECTOR_DATA;
+
+ if(ioctl(fd,CDROMCDXA,&cdxa)==-1) {
+ perror("CDROMCDXA");
+ return 0;
+ }
+ *offset = 0;
+#elif SUN_VCDREAD == SUN_MODE2READ
+ struct cdrom_read cdread;
+ cdread.cdread_lba = 4*vcd_get_msf();
+ cdread.cdread_bufaddr = vcd_buf;
+ cdread.cdread_buflen = 2336;
+
+ if(ioctl(fd,CDROMREADMODE2,&cdread)==-1) {
+ perror("CDROMREADMODE2");
+ return 0;
+ }
+ *offset = 8;
+#elif SUN_VCDREAD == SUN_SCSIREAD
+ struct uscsi_cmd sc;
+ union scsi_cdb cdb;
+ int lba = vcd_get_msf();
+ int blocks = 1;
+ int sector_type;
+ int sync, header_code, user_data, edc_ecc, error_field;
+ int sub_channel;
+
+ /* sector_type = 3; *//* mode2 */
+ sector_type = 5; /* mode2/form2 */
+ sync = 0;
+ header_code = 0;
+ user_data = 1;
+ edc_ecc = 0;
+ error_field = 0;
+ sub_channel = 0;
+
+ memset(&cdb, 0, sizeof(cdb));
+ memset(&sc, 0, sizeof(sc));
+ cdb.scc_cmd = 0xBE;
+ cdb.cdb_opaque[1] = (sector_type) << 2;
+ cdb.cdb_opaque[2] = (lba >> 24) & 0xff;
+ cdb.cdb_opaque[3] = (lba >> 16) & 0xff;
+ cdb.cdb_opaque[4] = (lba >> 8) & 0xff;
+ cdb.cdb_opaque[5] = lba & 0xff;
+ cdb.cdb_opaque[6] = (blocks >> 16) & 0xff;
+ cdb.cdb_opaque[7] = (blocks >> 8) & 0xff;
+ cdb.cdb_opaque[8] = blocks & 0xff;
+ cdb.cdb_opaque[9] = (sync << 7) |
+ (header_code << 5) |
+ (user_data << 4) |
+ (edc_ecc << 3) |
+ (error_field << 1);
+ cdb.cdb_opaque[10] = sub_channel;
+
+ sc.uscsi_cdb = (caddr_t)&cdb;
+ sc.uscsi_cdblen = 12;
+ sc.uscsi_bufaddr = vcd_buf;
+ sc.uscsi_buflen = 2336;
+ sc.uscsi_flags = USCSI_ISOLATE | USCSI_READ;
+ sc.uscsi_timeout = 20;
+ if (ioctl(fd, USCSICMD, &sc)) {
+ perror("USCSICMD: READ CD");
+ return -1;
+ }
+ if (sc.uscsi_status) {
+ fprintf(stderr, "scsi command failed with status %d\n", sc.uscsi_status);
+ return -1;
+ }
+ *offset = 0;
+ return 1;
+#else
+#error SUN_VCDREAD
+#endif
+}
+#endif /*sun*/
+
+
+//================== VCD CACHE =======================
+#ifdef VCD_CACHE
+
+static int vcd_cache_size=0;
+static char *vcd_cache_data=NULL;
+static int *vcd_cache_sectors=NULL;
+static int vcd_cache_index=0; // index to first free (or oldest) cache sector
+static int vcd_cache_current=-1;
+
+void vcd_cache_init(int s){
+ vcd_cache_size=s;
+ vcd_cache_sectors=malloc(s*sizeof(int));
+ vcd_cache_data=malloc(s*VCD_SECTOR_SIZE);
+ memset(vcd_cache_sectors,255,s*sizeof(int));
+}
+
+static inline void vcd_cache_seek(int sect){
+ vcd_cache_current=sect;
+}
+
+int vcd_cache_read(int fd,char* mem){
+ int i;
+ char* vcd_buf;
+
+ for(i=0;i<vcd_cache_size;i++)
+ if(vcd_cache_sectors[i]==vcd_cache_current){
+ // found in the cache! :)
+ vcd_buf=&vcd_cache_data[i*VCD_SECTOR_SIZE];
+ ++vcd_cache_current;
+ memcpy(mem,&vcd_buf[VCD_SECTOR_OFFS],VCD_SECTOR_DATA);
+ return VCD_SECTOR_DATA;
+ }
+ // NEW cache entry:
+ vcd_buf=&vcd_cache_data[vcd_cache_index*VCD_SECTOR_SIZE];
+ vcd_cache_sectors[vcd_cache_index]=vcd_cache_current;
+ ++vcd_cache_index;if(vcd_cache_index>=vcd_cache_size)vcd_cache_index=0;
+ // read data!
+ vcd_set_msf(vcd_cache_current);
+#if defined(linux) || defined(__bsdi__)
+ memcpy(vcd_buf,&vcd_entry.cdte_addr.msf,sizeof(struct cdrom_msf));
+ if(ioctl(fd,CDROMREADRAW,vcd_buf)==-1) return 0; // EOF?
+ memcpy(mem,&vcd_buf[VCD_SECTOR_OFFS],VCD_SECTOR_DATA);
+#elif defined(sun)
+ {
+ int offset;
+ if (sun_vcd_read(fd, &offset) <= 0) return 0;
+ memcpy(mem,&vcd_buf[offset],VCD_SECTOR_DATA);
+ }
+#endif
+ ++vcd_cache_current;
+ return VCD_SECTOR_DATA;
+}
+#endif
+
+#else /* linux || sun */
+
+int vcd_seek_to_track(int fd,int track)
+{
+ return -1;
+}
+
+int vcd_get_track_end(int fd,int track)
+{
+ return -1;
+}
+
+void vcd_read_toc(int fd)
+{
+}
+
+static char vcd_buf[VCD_SECTOR_SIZE];
+
+static int vcd_read(int fd,char *mem)
+{
+ return -1;
+}
+
+#endif /* !linux && !sun */
diff --git a/libmpdemux/vcd_read_fbsd.h b/libmpdemux/vcd_read_fbsd.h
new file mode 100644
index 0000000000..f21fb10b48
--- /dev/null
+++ b/libmpdemux/vcd_read_fbsd.h
@@ -0,0 +1,143 @@
+#include <sys/cdio.h>
+#include <sys/cdrio.h>
+
+//=================== VideoCD ==========================
+#define CDROM_LEADOUT 0xAA
+
+typedef struct {
+ uint8_t sync [12];
+ uint8_t header [4];
+ uint8_t subheader [8];
+ uint8_t data [2324];
+ uint8_t spare [4];
+} cdsector_t;
+
+static cdsector_t vcd_buf;
+static struct ioc_read_toc_single_entry vcd_entry;
+
+static inline void vcd_set_msf(unsigned int sect){
+ vcd_entry.entry.addr.msf.frame=sect%75;
+ sect=sect/75;
+ vcd_entry.entry.addr.msf.second=sect%60;
+ sect=sect/60;
+ vcd_entry.entry.addr.msf.minute=sect;
+}
+
+static inline unsigned int vcd_get_msf(){
+ return vcd_entry.entry.addr.msf.frame +
+ (vcd_entry.entry.addr.msf.second+
+ vcd_entry.entry.addr.msf.minute*60)*75;
+}
+
+int vcd_seek_to_track(int fd,int track){
+ vcd_entry.address_format = CD_MSF_FORMAT;
+ vcd_entry.track = track;
+ if (ioctl(fd, CDIOREADTOCENTRY, &vcd_entry)) {
+ perror("ioctl dif1");
+ return -1;
+ }
+ return VCD_SECTOR_DATA*vcd_get_msf();
+}
+
+int vcd_get_track_end(int fd,int track){
+ struct ioc_toc_header tochdr;
+ if (ioctl(fd,CDIOREADTOCHEADER,&tochdr)==-1)
+ { perror("read CDROM toc header: "); return -1; }
+ vcd_entry.address_format = CD_MSF_FORMAT;
+ vcd_entry.track = track<tochdr.ending_track?(track+1):CDROM_LEADOUT;
+ if (ioctl(fd, CDIOREADTOCENTRY, &vcd_entry)) {
+ perror("ioctl dif2");
+ return -1;
+ }
+ return VCD_SECTOR_DATA*vcd_get_msf();
+}
+
+void vcd_read_toc(int fd){
+ struct ioc_toc_header tochdr;
+ int i;
+ if (ioctl(fd,CDIOREADTOCHEADER,&tochdr)==-1)
+ { perror("read CDROM toc header: "); return; }
+ for (i=tochdr.starting_track ; i<=tochdr.ending_track ; i++){
+ struct ioc_read_toc_single_entry tocentry;
+
+ tocentry.track = i;
+ tocentry.address_format = CD_MSF_FORMAT;
+
+ if (ioctl(fd,CDIOREADTOCENTRY,&tocentry)==-1)
+ { perror("read CDROM toc entry: "); return; }
+
+ printf("track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d\n",
+ (int)tocentry.track,
+ (int)tocentry.entry.addr_type,
+ (int)tocentry.entry.control,
+ (int)tocentry.address_format,
+ (int)tocentry.entry.addr.msf.minute,
+ (int)tocentry.entry.addr.msf.second,
+ (int)tocentry.entry.addr.msf.frame
+ );
+ }
+}
+
+static int vcd_read(int fd,char *mem){
+
+ if (pread(fd,&vcd_buf,VCD_SECTOR_SIZE,vcd_get_msf()*VCD_SECTOR_SIZE)
+ != VCD_SECTOR_SIZE) return 0; // EOF?
+
+ vcd_entry.entry.addr.msf.frame++;
+ if (vcd_entry.entry.addr.msf.frame==75){
+ vcd_entry.entry.addr.msf.frame=0;
+ vcd_entry.entry.addr.msf.second++;
+ if (vcd_entry.entry.addr.msf.second==60){
+ vcd_entry.entry.addr.msf.second=0;
+ vcd_entry.entry.addr.msf.minute++;
+ }
+ }
+ memcpy(mem,vcd_buf.data,VCD_SECTOR_DATA);
+ return VCD_SECTOR_DATA;
+}
+
+//================== VCD CACHE =======================
+#ifdef VCD_CACHE
+
+static int vcd_cache_size=0;
+static char *vcd_cache_data=NULL;
+static int *vcd_cache_sectors=NULL;
+static int vcd_cache_index=0; // index to first free (or oldest) cache sector
+static int vcd_cache_current=-1;
+
+void vcd_cache_init(int s){
+ vcd_cache_size=s;
+ vcd_cache_sectors=malloc(s*sizeof(int));
+ vcd_cache_data=malloc(s*VCD_SECTOR_SIZE);
+ memset(vcd_cache_sectors,255,s*sizeof(int));
+}
+
+static inline void vcd_cache_seek(int sect){
+ vcd_cache_current=sect;
+}
+
+int vcd_cache_read(int fd,char* mem){
+int i;
+char* vcd_buf;
+ for(i=0;i<vcd_cache_size;i++)
+ if(vcd_cache_sectors[i]==vcd_cache_current){
+ // found in the cache! :)
+ vcd_buf=&vcd_cache_data[i*VCD_SECTOR_SIZE];
+ ++vcd_cache_current;
+ memcpy(mem,&vcd_buf[VCD_SECTOR_OFFS],VCD_SECTOR_DATA);
+ return VCD_SECTOR_DATA;
+ }
+ // NEW cache entry:
+ vcd_buf=&vcd_cache_data[vcd_cache_index*VCD_SECTOR_SIZE];
+ vcd_cache_sectors[vcd_cache_index]=vcd_cache_current;
+ ++vcd_cache_index;if(vcd_cache_index>=vcd_cache_size)vcd_cache_index=0;
+ // read data!
+ vcd_set_msf(vcd_cache_current);
+ memcpy(vcd_buf,&vcd_entry.entry.addr.msf,sizeof(struct cdrom_msf));
+/* if(ioctl(fd,CDROMREADRAW,vcd_buf)==-1) return 0; */ // EOF?
+ ++vcd_cache_current;
+ memcpy(mem,&vcd_buf[VCD_SECTOR_OFFS],VCD_SECTOR_DATA);
+ return VCD_SECTOR_DATA;
+}
+
+#endif