diff options
author | wm4 <wm4@nowhere> | 2013-07-07 23:54:11 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2013-07-07 23:54:11 +0200 |
commit | af0c41e162725b0edcd6c3d066a2dbef05a3b896 (patch) | |
tree | 607f2aa997815accec54e838cde124df845c7f38 /demux | |
parent | 8781e5a55c5f250e7c637a4cc9c4d8f91b227314 (diff) |
Remove old demuxers
Delete demux_avi, demux_asf, demux_mpg, demux_ts. libavformat does
better than them (except in rare corner cases), and the demuxers have
a bad influence on the rest of the code. Often they don't output
proper packets, and require additional audio and video parsing. Most
work only in --no-correct-pts mode.
Remove them to facilitate further cleanups.
Diffstat (limited to 'demux')
-rw-r--r-- | demux/asf.h | 251 | ||||
-rw-r--r-- | demux/asfguid.h | 89 | ||||
-rw-r--r-- | demux/asfheader.c | 721 | ||||
-rw-r--r-- | demux/asfheader.h | 28 | ||||
-rw-r--r-- | demux/aviheader.c | 674 | ||||
-rw-r--r-- | demux/aviheader.h | 382 | ||||
-rw-r--r-- | demux/aviprint.c | 197 | ||||
-rw-r--r-- | demux/aviprint.h | 35 | ||||
-rw-r--r-- | demux/demux.c | 140 | ||||
-rw-r--r-- | demux/demux.h | 71 | ||||
-rw-r--r-- | demux/demux_asf.c | 691 | ||||
-rw-r--r-- | demux/demux_avi.c | 899 | ||||
-rw-r--r-- | demux/demux_lavf.c | 2 | ||||
-rw-r--r-- | demux/demux_mkv.c | 3 | ||||
-rw-r--r-- | demux/demux_mpg.c | 1306 | ||||
-rw-r--r-- | demux/demux_ts.c | 3532 | ||||
-rw-r--r-- | demux/demux_ts.h | 24 | ||||
-rw-r--r-- | demux/extension.c | 25 | ||||
-rw-r--r-- | demux/mp3_hdr.c | 144 | ||||
-rw-r--r-- | demux/mp3_hdr.h | 36 | ||||
-rw-r--r-- | demux/mpeg_hdr.c | 539 | ||||
-rw-r--r-- | demux/mpeg_hdr.h | 55 | ||||
-rw-r--r-- | demux/ms_hdr.h | 8 | ||||
-rw-r--r-- | demux/parse_es.c | 158 | ||||
-rw-r--r-- | demux/parse_es.h | 45 | ||||
-rw-r--r-- | demux/stheader.h | 6 | ||||
-rw-r--r-- | demux/video.c | 527 |
27 files changed, 26 insertions, 10562 deletions
diff --git a/demux/asf.h b/demux/asf.h deleted file mode 100644 index db48f72edb..0000000000 --- a/demux/asf.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_ASF_H -#define MPLAYER_ASF_H - -#include <sys/types.h> -#include <inttypes.h> -#include "libavutil/common.h" -#include "compat/mpbswap.h" - -/////////////////////// -// 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 stream_id[16]; // stream GUID - uint64_t file_size; - uint64_t creation_time; //File creation time FILETIME 8 - uint64_t num_packets; //Number of packets UINT64 8 - uint64_t play_duration; //Timestamp of the end position UINT64 8 - uint64_t send_duration; //Duration of the playback UINT64 8 - uint64_t preroll; //Time to bufferize before playing UINT64 8 - uint32_t flags; //Unknown, maybe flags ( usually contains 2 ) UINT32 4 - uint32_t min_packet_size; //Min size of the packet, in bytes UINT32 4 - uint32_t max_packet_size; //Max size of the packet UINT32 4 - uint32_t max_bitrate; //Maximum bitrate of the media (sum of all the stream) -} 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 stream type -#if BYTE_ORDER == BIG_ENDIAN - #define ASF_STREAMING_CLEAR 0x2443 // $C - #define ASF_STREAMING_DATA 0x2444 // $D - #define ASF_STREAMING_END_TRANS 0x2445 // $E - #define ASF_STREAMING_HEADER 0x2448 // $H -#else - #define ASF_STREAMING_CLEAR 0x4324 // $C - #define ASF_STREAMING_DATA 0x4424 // $D - #define ASF_STREAMING_END_TRANS 0x4524 // $E - #define ASF_STREAMING_HEADER 0x4824 // $H -#endif - -// Definition of the differents type of ASF streaming -typedef enum { - ASF_Unknown_e, - ASF_Live_e, - ASF_Prerecorded_e, - ASF_Redirector_e, - ASF_PlainText_e, - ASF_Authenticate_e -} ASF_StreamType_e; - -typedef struct { - ASF_StreamType_e streaming_type; - int request; - int packet_size; - int *audio_streams,n_audio,*video_streams,n_video; - int audio_id, video_id; -} asf_http_streaming_ctrl_t; - - -/* - * Some macros to swap little endian structures read from an ASF file - * into machine endian format - */ -#if BYTE_ORDER == BIG_ENDIAN -#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)->creation_time = le2me_64((h)->creation_time); \ - (h)->num_packets = le2me_64((h)->num_packets); \ - (h)->play_duration = le2me_64((h)->play_duration); \ - (h)->send_duration = le2me_64((h)->send_duration); \ - (h)->preroll = le2me_64((h)->preroll); \ - (h)->flags = le2me_32((h)->flags); \ - (h)->min_packet_size = le2me_32((h)->min_packet_size); \ - (h)->max_packet_size = le2me_32((h)->max_packet_size); \ - (h)->max_bitrate = le2me_32((h)->max_bitrate); \ -} -#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); \ -} -#define le2me_ASF_stream_chunck_t(h) { \ - (h)->size = le2me_16((h)->size); \ - (h)->sequence_number = le2me_32((h)->sequence_number); \ - (h)->unknown = le2me_16((h)->unknown); \ - (h)->size_confirm = le2me_16((h)->size_confirm); \ -} -#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) /**/ -#define le2me_ASF_stream_chunck_t(h) /**/ -#endif - -// priv struct for the demuxer -struct asf_priv { - ASF_header_t header; - unsigned char* packet; - int scrambling_h; - int scrambling_w; - int scrambling_b; - unsigned packetsize; - double packetrate; - double movielength; - int asf_is_dvr_ms; - uint32_t asf_frame_state; - int asf_frame_start_found; - double dvr_last_vid_pts; - uint64_t vid_frame_ct; - uint64_t play_duration; - uint64_t num_packets; - int new_vid_frame_seg; - int *vid_repdata_sizes; - int *aud_repdata_sizes; - int vid_repdata_count; - int aud_repdata_count; - uint64_t avg_vid_frame_time; - uint64_t last_key_payload_time; - uint64_t last_aud_pts; - uint64_t last_aud_diff; - int found_first_key_frame; - uint32_t last_vid_seq; - int vid_ext_timing_index; - int aud_ext_timing_index; - int vid_ext_frame_index; - int know_frame_time; - unsigned bps; -}; - -#endif /* MPLAYER_ASF_H */ diff --git a/demux/asfguid.h b/demux/asfguid.h deleted file mode 100644 index e1dfed87d1..0000000000 --- a/demux/asfguid.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2001 Reimar Döffinger - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_ASFGUID_H -#define MPLAYER_ASFGUID_H - -#include <inttypes.h> -#include "libavutil/common.h" -#include "compat/mpbswap.h" - - -#define ASF_LOAD_GUID_PREFIX(guid) AV_RL32(guid) - -#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 -#define ASF_GUID_PREFIX_stream_group 0x7bf875ce -#define ASF_GUID_PREFIX_ext_audio_stream 0x31178C9D -#define ASF_GUID_PREFIX_ext_stream_embed_stream_header 0x3AFB65E2 -#define ASF_GUID_PREFIX_dvr_ms_timing_rep_data 0xFD3CC02A -#define ASF_GUID_PREFIX_dvr_ms_vid_frame_rep_data 0xDD6432CC - -/* -const char asf_audio_stream_guid[16] = {0x40, 0x9e, 0x69, 0xf8, - 0x4d, 0x5b, 0xcf, 0x11, 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b}; -const char asf_video_stream_guid[16] = {0xc0, 0xef, 0x19, 0xbc, - 0x4d, 0x5b, 0xcf, 0x11, 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b}; -*/ -static const char asf_stream_header_guid[16] = {0x91, 0x07, 0xdc, 0xb7, - 0xb7, 0xa9, 0xcf, 0x11, 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65}; -static const char asf_file_header_guid[16] = {0xa1, 0xdc, 0xab, 0x8c, - 0x47, 0xa9, 0xcf, 0x11, 0x8e, 0xe4, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65}; -static const char asf_content_desc_guid[16] = {0x33, 0x26, 0xb2, 0x75, - 0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c}; -static const char asf_stream_group_guid[16] = {0xce, 0x75, 0xf8, 0x7b, - 0x8d, 0x46, 0xd1, 0x11, 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2}; -static const char asf_data_chunk_guid[16] = {0x36, 0x26, 0xb2, 0x75, - 0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c}; -static const char asf_ext_stream_embed_stream_header[16] = {0xe2, 0x65, 0xfb, 0x3a, - 0xef, 0x47, 0xf2, 0x40, 0xac, 0x2c, 0x70, 0xa9, 0x0d, 0x71, 0xd3, 0x43}; -static const char asf_ext_stream_audio[16] = {0x9d, 0x8c, 0x17, 0x31, - 0xe1, 0x03, 0x28, 0x45, 0xb5, 0x82, 0x3d, 0xf9, 0xdb, 0x22, 0xf5, 0x03}; -static const char asf_ext_stream_header[16] = {0xCB, 0xA5, 0xE6, 0x14, - 0x72, 0xC6, 0x32, 0x43, 0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A}; -static const char asf_metadata_header[16] = {0xea, 0xcb, 0xf8, 0xc5, - 0xaf, 0x5b, 0x77, 0x48, 0x84, 0x67, 0xaa, 0x8c, 0x44, 0xfa, 0x4c, 0xca}; -static const char asf_content_encryption[16] = {0xfb, 0xb3, 0x11, 0x22, - 0x23, 0xbd, 0xd2, 0x11, 0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e}; -static const char asf_dvr_ms_timing_rep_data[16] = {0x2a, 0xc0, 0x3c,0xfd, - 0xdb, 0x06, 0xfa, 0x4c, 0x80, 0x1c, 0x72, 0x12, 0xd3, 0x87, 0x45, 0xe4}; -static const char asf_dvr_ms_vid_frame_rep_data[16] = {0xcc, 0x32, 0x64, 0xdd, - 0x29, 0xe2, 0xdb, 0x40, 0x80, 0xf6, 0xd2, 0x63, 0x28, 0xd2, 0x76, 0x1f}; - -static int find_asf_guid(char *buf, const char *guid, int cur_pos, int buf_len) -{ - int i; - for (i = cur_pos; i < buf_len - 19; i++) { - if (memcmp(&buf[i], guid, 16) == 0) - return i + 16 + 8; // point after guid + length - } - return -1; -} - -#endif /* MPLAYER_ASFGUID_H */ diff --git a/demux/asfheader.c b/demux/asfheader.c deleted file mode 100644 index e3f19840cd..0000000000 --- a/demux/asfheader.c +++ /dev/null @@ -1,721 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -// .asf fileformat docs from http://divx.euro.ru - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <libavutil/intreadwrite.h> -#include <libavutil/common.h> - -#include "config.h" -#include "core/mp_msg.h" - -#include "stream/stream.h" -#include "aviprint.h" -#include "demux.h" -#include "stheader.h" - -#include "asf.h" -#include "asfguid.h" -#include "asfheader.h" - -typedef struct { - // must be 0 for metadata record, might be non-zero for metadata lib record - uint16_t lang_list_index; - uint16_t stream_num; - uint16_t name_length; - uint16_t data_type; - uint32_t data_length; - uint16_t* name; - void* data; -} ASF_meta_record_t; - -static char* get_ucs2str(const uint16_t* inbuf, uint16_t inlen) -{ - char* outbuf = calloc(inlen, 2); - char* q; - int i; - - if (!outbuf) { - mp_tmsg(MSGT_HEADER, MSGL_ERR, "Memory allocation failed.\n"); - return NULL; - } - q = outbuf; - for (i = 0; i < inlen / 2; i++) { - uint8_t tmp; - PUT_UTF8(AV_RL16(&inbuf[i]), tmp, *q++ = tmp;) - } - return outbuf; -} - -static const 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_ext_audio_stream: - return "guid_ext_audio_stream"; - case ASF_GUID_PREFIX_ext_stream_embed_stream_header: - return "guid_ext_stream_embed_stream_header"; - 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"; - case ASF_GUID_PREFIX_dvr_ms_timing_rep_data: - return "guid_dvr_ms_timing_rep_data"; - case ASF_GUID_PREFIX_dvr_ms_vid_frame_rep_data: - return "guid_dvr_ms_vid_frame_rep_data"; - 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}; - struct asf_priv* asf = calloc(1,sizeof(*asf)); - asf->scrambling_h=asf->scrambling_w=asf->scrambling_b=1; - stream_read(demuxer->stream,(char*) &asf->header,sizeof(asf->header)); // header obj - le2me_ASF_header_t(&asf->header); // 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,asf->header.objh.guid,16)){ - mp_msg(MSGT_HEADER,MSGL_V,"ASF_check: not ASF guid!\n"); - free(asf); - return 0; // not ASF guid - } - if(asf->header.cno>256){ - mp_msg(MSGT_HEADER,MSGL_V,"ASF_check: invalid subchunks_no %d\n",(int) asf->header.cno); - free(asf); - return 0; // invalid header??? - } - demuxer->priv = asf; - return DEMUXER_TYPE_ASF; -} - -static int get_ext_stream_properties(char *buf, int buf_len, int stream_num, struct asf_priv* asf, int is_video) -{ - int pos=0; - uint8_t *buffer = &buf[0]; - uint64_t avg_ft av_unused; - unsigned bitrate; - - while ((pos = find_asf_guid(buf, asf_ext_stream_header, pos, buf_len)) >= 0) { - int this_stream_num, stnamect, payct, i; - int buf_max_index=pos+50; - if (buf_max_index > buf_len) return 0; - buffer = &buf[pos]; - - // the following info is available - // some of it may be useful but we're skipping it for now - // starttime(8 bytes), endtime(8), - // leak-datarate(4), bucket-datasize(4), init-bucket-fullness(4), - // alt-leak-datarate(4), alt-bucket-datasize(4), alt-init-bucket-fullness(4), - // max-object-size(4), - // flags(4) (reliable,seekable,no_cleanpoints?,resend-live-cleanpoints, rest of bits reserved) - - buffer += 8+8; - bitrate = AV_RL32(buffer); - buffer += 8*4; - this_stream_num=AV_RL16(buffer);buffer+=2; - - if (this_stream_num == stream_num) { - buf_max_index+=14; - if (buf_max_index > buf_len) return 0; - buffer+=2; //skip stream-language-id-index - avg_ft = AV_RL64(buffer); // provided in 100ns units - buffer+=8; - asf->bps = bitrate / 8; - - // after this are values for stream-name-count and - // payload-extension-system-count - // followed by associated info for each - stnamect = AV_RL16(buffer);buffer+=2; - payct = AV_RL16(buffer);buffer+=2; - - // need to read stream names if present in order - // to get lengths - values are ignored for now - for (i=0; i<stnamect; i++) { - int stream_name_len; - buf_max_index+=4; - if (buf_max_index > buf_len) return 0; - buffer+=2; //language_id_index - stream_name_len = AV_RL16(buffer);buffer+=2; - buffer+=stream_name_len; //stream_name - buf_max_index+=stream_name_len; - if (buf_max_index > buf_len) return 0; - } - - if (is_video) { - asf->vid_repdata_count = payct; - asf->vid_repdata_sizes = malloc(payct*sizeof(int)); - } else { - asf->aud_repdata_count = payct; - asf->aud_repdata_sizes = malloc(payct*sizeof(int)); - } - - for (i=0; i<payct; i++) { - int payload_len; - buf_max_index+=22; - if (buf_max_index > buf_len) return 0; - // Each payload extension definition starts with a GUID. - // In dvr-ms files one of these indicates the presence an - // extension that contains pts values and this is always present - // in the video and audio streams. - // Another GUID indicates the presence of an extension - // that contains useful video frame demuxing information. - // Note that the extension data in each packet does not contain - // these GUIDs and that this header section defines the order the data - // will appear in. - if (memcmp(buffer, asf_dvr_ms_timing_rep_data, 16) == 0) { - if (is_video) - asf->vid_ext_timing_index = i; - else - asf->aud_ext_timing_index = i; - } else if (is_video && memcmp(buffer, asf_dvr_ms_vid_frame_rep_data, 16) == 0) - asf->vid_ext_frame_index = i; - buffer+=16; - - payload_len = AV_RL16(buffer);buffer+=2; - - if (is_video) - asf->vid_repdata_sizes[i] = payload_len; - else - asf->aud_repdata_sizes[i] = payload_len; - buffer+=4;//sys_len - } - - return 1; - } - } - return 1; -} - -#define CHECKDEC(l, n) if (((l) -= (n)) < 0) return 0 -static char* read_meta_record(ASF_meta_record_t* dest, char* buf, - int* buf_len) -{ - CHECKDEC(*buf_len, 2 + 2 + 2 + 2 + 4); - dest->lang_list_index = AV_RL16(buf); - dest->stream_num = AV_RL16(&buf[2]); - dest->name_length = AV_RL16(&buf[4]); - dest->data_type = AV_RL16(&buf[6]); - dest->data_length = AV_RL32(&buf[8]); - buf += 2 + 2 + 2 + 2 + 4; - CHECKDEC(*buf_len, dest->name_length); - dest->name = (uint16_t*)buf; - buf += dest->name_length; - CHECKDEC(*buf_len, dest->data_length); - dest->data = buf; - buf += dest->data_length; - return buf; -} - -static int get_meta(char *buf, int buf_len, int this_stream_num, - float* asp_ratio) -{ - int pos = 0; - uint16_t records_count; - uint16_t x = 0, y = 0; - - if ((pos = find_asf_guid(buf, asf_metadata_header, pos, buf_len)) < 0) - return 0; - - CHECKDEC(buf_len, pos); - buf += pos; - CHECKDEC(buf_len, 2); - records_count = AV_RL16(buf); - buf += 2; - - while (records_count--) { - ASF_meta_record_t record_entry; - char* name; - - if (!(buf = read_meta_record(&record_entry, buf, &buf_len))) - return 0; - /* reserved, must be zero */ - if (record_entry.lang_list_index) - continue; - /* match stream number: 0 to match all */ - if (record_entry.stream_num && record_entry.stream_num != this_stream_num) - continue; - if (!(name = get_ucs2str(record_entry.name, record_entry.name_length))) { - mp_tmsg(MSGT_HEADER, MSGL_ERR, "Memory allocation failed.\n"); - continue; - } - if (strcmp(name, "AspectRatioX") == 0) - x = AV_RL16(record_entry.data); - else if (strcmp(name, "AspectRatioY") == 0) - y = AV_RL16(record_entry.data); - free(name); - } - if (x && y) { - *asp_ratio = (float)x / (float)y; - return 1; - } - return 0; -} - -static int is_drm(char* buf, int buf_len) -{ - uint32_t data_len, type_len, key_len, url_len; - int pos = find_asf_guid(buf, asf_content_encryption, 0, buf_len); - - if (pos < 0) - return 0; - - CHECKDEC(buf_len, pos + 4); - buf += pos; - data_len = AV_RL32(buf); - buf += 4; - CHECKDEC(buf_len, data_len); - buf += data_len; - type_len = AV_RL32(buf); - if (type_len < 4) - return 0; - CHECKDEC(buf_len, 4 + type_len + 4); - buf += 4; - - if (buf[0] != 'D' || buf[1] != 'R' || buf[2] != 'M' || buf[3] != '\0') - return 0; - - buf += type_len; - key_len = AV_RL32(buf); - CHECKDEC(buf_len, key_len + 4); - buf += 4; - - buf[key_len - 1] = '\0'; - mp_msg(MSGT_HEADER, MSGL_V, "DRM Key ID: %s\n", buf); - - buf += key_len; - url_len = AV_RL32(buf); - CHECKDEC(buf_len, url_len); - buf += 4; - - buf[url_len - 1] = '\0'; - mp_tmsg(MSGT_HEADER, MSGL_INFO, "DRM License URL: %s\n", buf); - return 1; -} - -static int asf_init_audio_stream(demuxer_t *demuxer,struct asf_priv* asf, sh_audio_t* sh_audio, ASF_stream_header_t *streamh, int *ppos, uint8_t** buf, char *hdr, unsigned int hdr_len) -{ - uint8_t *buffer = *buf; - int pos = *ppos; - - sh_audio->wf=calloc(FFMAX(streamh->type_size, sizeof(*sh_audio->wf)), 1); - memcpy(sh_audio->wf,buffer,streamh->type_size); - le2me_WAVEFORMATEX(sh_audio->wf); - sh_audio->format=sh_audio->wf->wFormatTag; - mp_set_audio_codec_from_tag(sh_audio); - if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_audio->wf,MSGL_V); - if(ASF_LOAD_GUID_PREFIX(streamh->concealment)==ASF_GUID_PREFIX_audio_conceal_interleave){ - buffer = &hdr[pos]; - pos += streamh->stream_size; - if (pos > hdr_len) return 0; - asf->scrambling_h=buffer[0]; - asf->scrambling_w=(buffer[2]<<8)|buffer[1]; - asf->scrambling_b=(buffer[4]<<8)|buffer[3]; - if(asf->scrambling_b>0){ - 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); - return 1; -} - -static int find_backwards_asf_guid(char *buf, const char *guid, int cur_pos) -{ - int i; - for (i=cur_pos-16; i>0; i--) { - if (memcmp(&buf[i], guid, 16) == 0) - return i + 16 + 8; // point after guid + length - } - return -1; -} - -int read_asf_header(demuxer_t *demuxer,struct asf_priv* asf){ - int hdr_len = asf->header.objh.size - sizeof(asf->header); - int hdr_skip = 0; - char *hdr = NULL; - char guid_buffer[16]; - int pos, start = stream_tell(demuxer->stream); - uint32_t* streams = NULL; - int audio_streams=0; - int video_streams=0; - uint16_t stream_count=0; - int best_video = -1; - int best_audio = -1; - uint64_t data_len; - ASF_stream_header_t *streamh; - uint8_t *buffer; - int audio_pos=0; - - if(hdr_len < 0) { - mp_msg(MSGT_HEADER, MSGL_FATAL, "Header size is too small.\n"); - return 0; - } - - if (hdr_len > 1024 * 1024) { - mp_tmsg(MSGT_HEADER, MSGL_ERR, "FATAL: header size bigger than 1 MB (%d)!\nPlease contact MPlayer authors, and upload/send this file.\n", - hdr_len); - hdr_skip = hdr_len - 1024 * 1024; - hdr_len = 1024 * 1024; - } - hdr = malloc(hdr_len); - if (!hdr) { - mp_tmsg(MSGT_HEADER, MSGL_FATAL, "Could not allocate %d bytes for header.\n", - hdr_len); - return 0; - } - stream_read(demuxer->stream, hdr, hdr_len); - if (hdr_skip) - stream_skip(demuxer->stream, hdr_skip); - if (stream_eof(demuxer->stream)) { - mp_tmsg(MSGT_HEADER, MSGL_FATAL, "EOF while reading ASF header, broken/incomplete file?\n"); - goto err_out; - } - - if (is_drm(hdr, hdr_len)) - mp_tmsg(MSGT_HEADER, MSGL_FATAL, "This file has been encumbered with DRM encryption, it will not play in MPlayer!\n"); - - if ((pos = find_asf_guid(hdr, asf_ext_stream_audio, 0, hdr_len)) >= 0) - { - // Special case: found GUID for dvr-ms audio. - // Now skip back to associated stream header. - int sh_pos=0; - - sh_pos = find_backwards_asf_guid(hdr, asf_stream_header_guid, pos); - - if (sh_pos > 0) { - sh_audio_t *sh_audio; - - mp_msg(MSGT_HEADER, MSGL_V, "read_asf_header found dvr-ms audio stream header pos=%d\n", sh_pos); - // found audio stream header - following code reads header and - // initializes audio stream. - audio_pos = pos - 16 - 8; - streamh = (ASF_stream_header_t *)&hdr[sh_pos]; - le2me_ASF_stream_header_t(streamh); - audio_pos += 64; //16+16+4+4+4+16+4; - buffer = &hdr[audio_pos]; - sh_audio=new_sh_audio(demuxer,streamh->stream_no & 0x7F); - sh_audio->needs_parsing = 1; - mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[%s] Audio stream found, -aid %d\n", "asfheader", streamh->stream_no & 0x7F); - ++audio_streams; - if (!asf_init_audio_stream(demuxer, asf, sh_audio, streamh, &audio_pos, &buffer, hdr, hdr_len)) - goto len_err_out; - if (!get_ext_stream_properties(hdr, hdr_len, streamh->stream_no, asf, 0)) - goto len_err_out; - } - } - // find stream headers - // only reset pos if we didnt find dvr_ms audio stream - // if we did find it then we want to avoid reading its header twice - if (audio_pos == 0) - pos = 0; - - while ((pos = find_asf_guid(hdr, asf_stream_header_guid, pos, hdr_len)) >= 0) - { - streamh = (ASF_stream_header_t *)&hdr[pos]; - pos += sizeof(ASF_stream_header_t); - if (pos > hdr_len) goto len_err_out; - le2me_ASF_stream_header_t(streamh); - 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", pos + start); - // type-specific data: - buffer = &hdr[pos]; - pos += streamh->type_size; - if (pos > hdr_len) goto len_err_out; - 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); - mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[%s] Audio stream found, -aid %d\n", "asfheader", streamh->stream_no & 0x7F); - ++audio_streams; - if (!asf_init_audio_stream(demuxer, asf, sh_audio, streamh, &pos, &buffer, hdr, hdr_len)) - goto len_err_out; - //if(demuxer->audio->id==-1) demuxer->audio->id=streamh.stream_no & 0x7F; - break; - } - case ASF_GUID_PREFIX_video_stream: { - unsigned int len; - float asp_ratio; - sh_video_t* sh_video=new_sh_video(demuxer,streamh->stream_no & 0x7F); - mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[%s] Video stream found, -vid %d\n", "asfheader", streamh->stream_no & 0x7F); - len=streamh->type_size-(4+4+1+2); - ++video_streams; -// sh_video->bih=malloc(chunksize); memset(sh_video->bih,0,chunksize); - sh_video->bih=calloc((len<sizeof(*sh_video->bih))?sizeof(*sh_video->bih):len,1); - memcpy(sh_video->bih,&buffer[4+4+1+2],len); - le2me_BITMAPINFOHEADER(sh_video->bih); - if (sh_video->bih->biSize > len && sh_video->bih->biSize > sizeof(*sh_video->bih)) - sh_video->bih->biSize = len; - if (sh_video->bih->biCompression == mmioFOURCC('D', 'V', 'R', ' ')) { - //mp_tmsg(MSGT_DEMUXER, MSGL_WARN, "DVR will probably only work with libavformat, try -demuxer 35 if you have problems\n"); - //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; - asf->asf_frame_state=-1; - asf->asf_frame_start_found=0; - asf->asf_is_dvr_ms=1; - asf->dvr_last_vid_pts=0.0; - } else asf->asf_is_dvr_ms=0; - if (!get_ext_stream_properties(hdr, hdr_len, streamh->stream_no, asf, 1)) - goto len_err_out; - if (get_meta(hdr, hdr_len, streamh->stream_no, &asp_ratio)) { - sh_video->aspect = asp_ratio * sh_video->bih->biWidth / - sh_video->bih->biHeight; - } - sh_video->i_bps = asf->bps; - sh_video->format = sh_video->bih->biCompression; - mp_set_video_codec_from_tag(sh_video); - sh_video->format = mp_video_fourcc_alias(sh_video->format); - - if( mp_msg_test(MSGT_DEMUX,MSGL_V) ) print_video_header(sh_video->bih, MSGL_V); - //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); - } - - // find file header - pos = find_asf_guid(hdr, asf_file_header_guid, 0, hdr_len); - if (pos >= 0) { - ASF_file_header_t *fileh = (ASF_file_header_t *)&hdr[pos]; - pos += sizeof(ASF_file_header_t); - if (pos > hdr_len) goto len_err_out; - le2me_ASF_file_header_t(fileh); - mp_msg(MSGT_HEADER, MSGL_V, "ASF: packets: %d flags: %d " - "max_packet_size: %d min_packet_size: %d max_bitrate: %d " - "preroll: %d\n", - (int)fileh->num_packets, (int)fileh->flags, - (int)fileh->min_packet_size, (int)fileh->max_packet_size, - (int)fileh->max_bitrate, (int)fileh->preroll); - asf->packetsize=fileh->max_packet_size; - asf->packet=malloc(asf->packetsize); // !!! - asf->packetrate=fileh->max_bitrate/8.0/(double)asf->packetsize; - asf->movielength=FFMAX(0.0, (fileh->play_duration / 10000.0 - fileh->preroll) / 1000.0); - } - - // find content header - pos = find_asf_guid(hdr, asf_content_desc_guid, 0, hdr_len); - if (pos >= 0) { - ASF_content_description_t *contenth = (ASF_content_description_t *)&hdr[pos]; - char *string=NULL; - uint16_t* wstring = NULL; - uint16_t len; - pos += sizeof(ASF_content_description_t); - if (pos > hdr_len) goto len_err_out; - le2me_ASF_content_description_t(contenth); - mp_msg(MSGT_HEADER,MSGL_V,"\n"); - // extract the title - if((len = contenth->title_size) != 0) { - wstring = (uint16_t*)&hdr[pos]; - pos += len; - if (pos > hdr_len) goto len_err_out; - if ((string = get_ucs2str(wstring, len))) { - mp_msg(MSGT_HEADER,MSGL_V," Title: %s\n", string); - demux_info_add(demuxer, "title", string); - free(string); - } - } - // extract the author - if((len = contenth->author_size) != 0) { - wstring = (uint16_t*)&hdr[pos]; - pos += len; - if (pos > hdr_len) goto len_err_out; - if ((string = get_ucs2str(wstring, len))) { - mp_msg(MSGT_HEADER,MSGL_V," Author: %s\n", string); - demux_info_add(demuxer, "author", string); - free(string); - } - } - // extract the copyright - if((len = contenth->copyright_size) != 0) { - wstring = (uint16_t*)&hdr[pos]; - pos += len; - if (pos > hdr_len) goto len_err_out; - if ((string = get_ucs2str(wstring, len))) { - mp_msg(MSGT_HEADER,MSGL_V," Copyright: %s\n", string); - demux_info_add(demuxer, "copyright", string); - free(string); - } - } - // extract the comment - if((len = contenth->comment_size) != 0) { - wstring = (uint16_t*)&hdr[pos]; - pos += len; - if (pos > hdr_len) goto len_err_out; - if ((string = get_ucs2str(wstring, len))) { - mp_msg(MSGT_HEADER,MSGL_V," Comment: %s\n", string); - demux_info_add(demuxer, "comments", string); - free(string); - } - } - // extract the rating - if((len = contenth->rating_size) != 0) { - wstring = (uint16_t*)&hdr[pos]; - pos += len; - if (pos > hdr_len) goto len_err_out; - if ((string = get_ucs2str(wstring, len))) { - mp_msg(MSGT_HEADER,MSGL_V," Rating: %s\n", string); - free(string); - } - } - mp_msg(MSGT_HEADER,MSGL_V,"\n"); - } - - // find content header - pos = find_asf_guid(hdr, asf_stream_group_guid, 0, hdr_len); - if (pos >= 0) { - int max_streams = (hdr_len - pos - 2) / 6; - uint16_t stream_id, i; - uint32_t max_bitrate; - char *ptr = &hdr[pos]; - mp_msg(MSGT_HEADER,MSGL_V,"============ ASF Stream group == START ===\n"); - if(max_streams <= 0) goto len_err_out; - stream_count = AV_RL16(ptr); - ptr += sizeof(uint16_t); - if(stream_count > max_streams) stream_count = max_streams; - if(stream_count > 0) - streams = malloc(2*stream_count*sizeof(uint32_t)); - mp_msg(MSGT_HEADER,MSGL_V," stream count=[0x%x][%u]\n", stream_count, stream_count ); - for( i=0 ; i<stream_count ; i++ ) { - stream_id = AV_RL16(ptr); - ptr += sizeof(uint16_t); - max_bitrate = AV_RL32(ptr); - ptr += sizeof(uint32_t); - mp_msg(MSGT_HEADER,MSGL_V," stream id=[0x%x][%u]\n", stream_id, stream_id ); - mp_msg(MSGT_HEADER,MSGL_V," max bitrate=[0x%x][%u]\n", max_bitrate, max_bitrate ); - streams[2*i] = stream_id; - streams[2*i+1] = max_bitrate; - } - mp_msg(MSGT_HEADER,MSGL_V,"============ ASF Stream group == END ===\n"); - } - free(hdr); - hdr = NULL; - start = stream_tell(demuxer->stream); // start of first data chunk - stream_read(demuxer->stream, guid_buffer, 16); - if (memcmp(guid_buffer, asf_data_chunk_guid, 16) != 0) { - mp_tmsg(MSGT_HEADER, MSGL_FATAL, "No data chunk following header!\n"); - free(streams); - streams = NULL; - return 0; - } - // read length of chunk - data_len = stream_read_qword_le(demuxer->stream); - demuxer->movi_start = stream_tell(demuxer->stream) + 26; - demuxer->movi_end = start + data_len; - mp_msg(MSGT_HEADER, MSGL_V, "Found movie at 0x%X - 0x%X\n", - (int)demuxer->movi_start, (int)demuxer->movi_end); - -if(streams) { - // stream selection is done in the network code, it shouldn't be done here - // as the servers often do not care about what we requested. -#if 0 - uint32_t vr = 0, ar = 0,i; -#ifdef CONFIG_NETWORKING - if( demuxer->stream->streaming_ctrl!=NULL ) { - if( demuxer->stream->streaming_ctrl->bandwidth!=0 && demuxer->stream->streaming_ctrl->data!=NULL ) { - best_audio = ((asf_http_streaming_ctrl_t*)demuxer->stream->streaming_ctrl->data)->audio_id; - best_video = ((asf_http_streaming_ctrl_t*)demuxer->stream->streaming_ctrl->data)->video_id; - } - } else -#endif - for(i = 0; i < stream_count; i++) { - uint32_t id = streams[2*i]; - uint32_t rate = streams[2*i+1]; - if(demuxer->v_streams[id] && rate > vr) { - vr = rate; - best_video = id; - } else if(demuxer->a_streams[id] && rate > ar) { - ar = rate; - best_audio = id; - } - } -#endif - free(streams); - streams = NULL; -} - -mp_msg(MSGT_HEADER,MSGL_V,"ASF: %d audio and %d video streams found\n",audio_streams,video_streams); -if(!audio_streams) demuxer->audio->id=-2; // nosound -else if(best_audio > 0 && demuxer->audio->id == -1) demuxer->audio->id=best_audio; -if(!video_streams){ - if(!audio_streams){ - mp_tmsg(MSGT_HEADER,MSGL_ERR,"ASF: no audio or video headers found - broken file?\n"); - return 0; - } - demuxer->video->id=-2; // audio-only -} else if (best_video > 0 && demuxer->video->id == -1) demuxer->video->id = best_video; - -#if 0 -if( mp_msg_test(MSGT_HEADER,MSGL_V) ){ - 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 - -return 1; - -len_err_out: - mp_tmsg(MSGT_HEADER, MSGL_FATAL, "Invalid length in ASF header!\n"); -err_out: - free(hdr); - free(streams); - return 0; -} diff --git a/demux/asfheader.h b/demux/asfheader.h deleted file mode 100644 index 3741f22cd6..0000000000 --- a/demux/asfheader.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_ASFHEADER_H -#define MPLAYER_ASFHEADER_H - -#include "asf.h" -#include "demux.h" - -int asf_check_header(demuxer_t *demuxer); -int read_asf_header(demuxer_t *demuxer, struct asf_priv *asf); - -#endif /* MPLAYER_ASFHEADER_H */ diff --git a/demux/aviheader.c b/demux/aviheader.c deleted file mode 100644 index c1b9c59692..0000000000 --- a/demux/aviheader.c +++ /dev/null @@ -1,674 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> - -#include <libavutil/common.h> -#include <libavutil/intreadwrite.h> - -#include "config.h" -#include "core/mp_msg.h" - -#include "stream/stream.h" -#include "demux.h" -#include "stheader.h" -#include "aviprint.h" -#include "aviheader.h" - -static MainAVIHeader avih; - -static int odml_get_vstream_id(int id, unsigned char res[]) -{ - if ((char)(id >> 16) == 'd') { - if (res) { - res[0] = id; - res[1] = id >> 8; - } - return 1; - } - return 0; -} - -static int avi_idx_cmp(const void *elem1, const void *elem2) -{ - register int64_t a = AVI_IDX_OFFSET((AVIINDEXENTRY *)elem1); - register int64_t b = AVI_IDX_OFFSET((AVIINDEXENTRY *)elem2); - return (a > b) - (b > a); -} - -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; -int64_t list_end=0; - -//---- AVI header: -priv->idx_size=0; -priv->audio_streams=0; -while(1){ - int id=stream_read_dword_le(demuxer->stream); - unsigned chunksize,size2; - static int last_fccType=0; - static int last_fccHandler=0; - char* hdr=NULL; - // - if(stream_eof(demuxer->stream)) break; - // - if(id==mmioFOURCC('L','I','S','T')){ - unsigned len=stream_read_dword_le(demuxer->stream); // list size - id=stream_read_dword_le(demuxer->stream); // list type - mp_msg(MSGT_HEADER,MSGL_DBG2,"LIST %.4s len=%u\n",(char *) &id,len); - if(len >= 4) { - len -= 4; - list_end=stream_tell(demuxer->stream)+((len+1)&(~1)); - } else { - mp_tmsg(MSGT_HEADER,MSGL_WARN,"** empty list?!\n"); - list_end = 0; - } - mp_msg(MSGT_HEADER,MSGL_V,"list_end=0x%X\n",(int)list_end); - if(id==listtypeAVIMOVIE){ - // found MOVI header - if(!demuxer->movi_start) demuxer->movi_start=stream_tell(demuxer->stream); - demuxer->movi_end=stream_tell(demuxer->stream)+len; - mp_tmsg(MSGT_HEADER,MSGL_V,"Found movie at 0x%X - 0x%X\n",(int)demuxer->movi_start,(int)demuxer->movi_end); - if(demuxer->stream->end_pos>demuxer->movi_end) demuxer->movi_end=demuxer->stream->end_pos; - if(index_mode==-2 || index_mode==2 || index_mode==0) - break; // reading from non-seekable source (stdin) or forced index or no index forced - if(list_end>0) stream_seek(demuxer->stream,list_end); // skip movi - list_end=0; - } - continue; - } - size2=stream_read_dword_le(demuxer->stream); - mp_msg(MSGT_HEADER,MSGL_DBG2,"CHUNK %.4s len=%u\n",(char *) &id,size2); - chunksize=(size2+1)&(~1); - switch(id){ - - // Indicates where the subject of the file is archived - case mmioFOURCC('I','A','R','L'): hdr="Archival Location";break; - // Lists the artist of the original subject of the file; - // for example, "Michaelangelo." - case mmioFOURCC('I','A','R','T'): hdr="Artist";break; - // Lists the name of the person or organization that commissioned - // the subject of the file; for example "Pope Julian II." - case mmioFOURCC('I','C','M','S'): hdr="Commissioned";break; - // Provides general comments about the file or the subject - // of the file. If the comment is several sentences long, end each - // sentence with a period. Do not include new-line characters. - case mmioFOURCC('I','C','M','T'): hdr="Comments";break; - // Records the copyright information for the file; for example, - // "Copyright Encyclopedia International 1991." If there are multiple - // copyrights, separate them by semicolon followed by a space. - case mmioFOURCC('I','C','O','P'): hdr="Copyright";break; - // Describes whether an image has been cropped and, if so, how it - // was cropped; for example, "lower-right corner." - case mmioFOURCC('I','C','R','D'): hdr="Creation Date";break; - // Describes whether an image has been cropped and, if so, how it - // was cropped; for example, "lower-right corner." - case mmioFOURCC('I','C','R','P'): hdr="Cropped";break; - // Specifies the size of the original subject of the file; for - // example, "8.5 in h, 11 in w." - case mmioFOURCC('I','D','I','M'): hdr="Dimensions";break; - // Stores dots per inch setting of the digitizer used to - // produce the file, such as "300." - case mmioFOURCC('I','D','P','I'): hdr="Dots Per Inch";break; - // Stores the of the engineer who worked on the file. If there are - // multiple engineers, separate the names by a semicolon and a blank; - // for example, "Smith, John; Adams, Joe." - case mmioFOURCC('I','E','N','G'): hdr="Engineer";break; - // Describes the original work, such as "landscape,", "portrait," - // "still liefe," etc. - case mmioFOURCC('I','G','N','R'): hdr="Genre";break; - // Provides a list of keywords that refer to the file or subject of the - // file. Separate multiple keywords with a semicolon and a blank; - // for example, "Seattle, aerial view; scenery." - case mmioFOURCC('I','K','E','Y'): hdr="Keywords";break; - // ILGT - Describes the changes in the lightness settings on the digitizer - // required to produce the file. Note that the format of this information - // depends on the hardware used. - case mmioFOURCC('I','L','G','T'): hdr="Lightness";break; - // IMED - Decribes the original subject of the file, such as - // "computer image," "drawing," "lithograph," and so on. - case mmioFOURCC('I','M','E','D'): hdr="Medium";break; - // INAM - Stores the title of the subject of the file, such as - // "Seattle from Above." - case mmioFOURCC('I','N','A','M'): hdr="Title";break; - // IPLT - Specifies the number of colors requested when digitizing - // an image, such as "256." - case mmioFOURCC('I','P','L','T'): hdr="Palette Setting";break; - // IPRD - Specifies the name of title the file was originally intended - // for, such as "Encyclopedia of Pacific Northwest Geography." - case mmioFOURCC('I','P','R','D'): hdr="Product";break; - // ISBJ - Decsribes the contents of the file, such as - // "Aerial view of Seattle." - case mmioFOURCC('I','S','B','J'): hdr="Subject";break; - // ISFT - Identifies the name of the software packages used to create the - // file, such as "Microsoft WaveEdit" - case mmioFOURCC('I','S','F','T'): hdr="Software";break; - // ISHP - Identifies the change in sharpness for the digitizer - // required to produce the file (the format depends on the hardware used). - case mmioFOURCC('I','S','H','P'): hdr="Sharpness";break; - // ISRC - Identifies the name of the person or organization who - // supplied the original subject of the file; for example, "Try Research." - case mmioFOURCC('I','S','R','C'): hdr="Source";break; - // ISRF - Identifies the original form of the material that was digitized, - // such as "slide," "paper," "map," and so on. This is not necessarily - // the same as IMED - case mmioFOURCC('I','S','R','F'): hdr="Source Form";break; - // ITCH - Identifies the technician who digitized the subject file; - // for example, "Smith, John." - case mmioFOURCC('I','T','C','H'): hdr="Technician";break; - case mmioFOURCC('I','S','M','P'): hdr="Time Code";break; - case mmioFOURCC('I','D','I','T'): hdr="Digitization Time";break; - - case ckidAVIMAINHDR: // read 'avih' - stream_read(demuxer->stream,(char*) &avih,FFMIN(size2,sizeof(avih))); - le2me_MainAVIHeader(&avih); // swap to machine endian - chunksize-=FFMIN(size2,sizeof(avih)); - if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_avih(&avih,MSGL_V); // else print_avih_flags(&avih,MSGL_V); - break; - case ckidSTREAMHEADER: { // read 'strh' - AVIStreamHeader h; - stream_read(demuxer->stream,(char*) &h,FFMIN(size2,sizeof(h))); - le2me_AVIStreamHeader(&h); // swap to machine endian - chunksize-=FFMIN(size2,sizeof(h)); - ++stream_id; - if(h.fccType==streamtypeVIDEO){ - sh_video=new_sh_video(demuxer,stream_id); - mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[%s] Video stream found, -vid %d\n", "aviheader", stream_id); - memcpy(&sh_video->video,&h,sizeof(h)); - sh_video->stream_delay = (float)sh_video->video.dwStart * sh_video->video.dwScale/sh_video->video.dwRate; - } else - if(h.fccType==streamtypeAUDIO){ - sh_audio=new_sh_audio(demuxer,stream_id); - mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[%s] Audio stream found, -aid %d\n", "aviheader", stream_id); - memcpy(&sh_audio->audio,&h,sizeof(h)); - sh_audio->stream_delay = (float)sh_audio->audio.dwStart * sh_audio->audio.dwScale/sh_audio->audio.dwRate; - sh_audio->needs_parsing = 1; - } - last_fccType=h.fccType; - last_fccHandler=h.fccHandler; - if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_strh(&h,MSGL_V); - break; } - case mmioFOURCC('i', 'n', 'd', 'x'): { - uint32_t i; - avisuperindex_chunk *s; - - if(!index_mode) break; - - if(chunksize<=24){ - break; - } - priv->suidx_size++; - priv->suidx = realloc_struct(priv->suidx, priv->suidx_size, sizeof (avisuperindex_chunk)); - s = &priv->suidx[priv->suidx_size-1]; - - chunksize-=24; - memcpy(s->fcc, "indx", 4); - s->dwSize = size2; - s->wLongsPerEntry = stream_read_word_le(demuxer->stream); - s->bIndexSubType = stream_read_char(demuxer->stream); - s->bIndexType = stream_read_char(demuxer->stream); - s->nEntriesInUse = stream_read_dword_le(demuxer->stream); - AV_WN32(s->dwChunkId, stream_read_dword_le(demuxer->stream)); - stream_read(demuxer->stream, (char *)s->dwReserved, 3*4); - memset(s->dwReserved, 0, 3*4); - - print_avisuperindex_chunk(s,MSGL_V); - - // Check and fix this useless crap - if(s->wLongsPerEntry != sizeof (avisuperindex_entry)/4) { - mp_msg (MSGT_HEADER, MSGL_WARN, "Broken super index chunk size: %u\n",s->wLongsPerEntry); - s->wLongsPerEntry = sizeof(avisuperindex_entry)/4; - } - if( ((chunksize/4)/s->wLongsPerEntry) < s->nEntriesInUse){ - mp_msg (MSGT_HEADER, MSGL_WARN, "Broken super index chunk\n"); - s->nEntriesInUse = (chunksize/4)/s->wLongsPerEntry; - } - - s->aIndex = calloc(s->nEntriesInUse, sizeof (avisuperindex_entry)); - s->stdidx = calloc(s->nEntriesInUse, sizeof (avistdindex_chunk)); - - // now the real index of indices - for (i=0; i<s->nEntriesInUse; i++) { - chunksize-=16; - s->aIndex[i].qwOffset = stream_read_qword_le(demuxer->stream); - s->aIndex[i].dwSize = stream_read_dword_le(demuxer->stream); - s->aIndex[i].dwDuration = stream_read_dword_le(demuxer->stream); - mp_msg (MSGT_HEADER, MSGL_V, "ODML (%.4s): [%d] 0x%016"PRIx64" 0x%04x %u\n", - s->dwChunkId, i, - (uint64_t)s->aIndex[i].qwOffset, s->aIndex[i].dwSize, s->aIndex[i].dwDuration); - } - - break; } - case ckidSTREAMFORMAT: { // read 'strf' - if(last_fccType==streamtypeVIDEO){ - sh_video->bih=calloc(FFMAX(chunksize, sizeof(*sh_video->bih)), 1); -// sh_video->bih=malloc(chunksize); memset(sh_video->bih,0,chunksize); - mp_tmsg(MSGT_HEADER,MSGL_V,"Found 'bih', %u bytes of %zu\n",chunksize,sizeof(*sh_video->bih)); - stream_read(demuxer->stream,(char*) sh_video->bih,chunksize); - le2me_BITMAPINFOHEADER(sh_video->bih); // swap to machine endian - if (sh_video->bih->biSize > chunksize && sh_video->bih->biSize > sizeof(*sh_video->bih)) - sh_video->bih->biSize = chunksize; - // fixup MS-RLE header (seems to be broken for <256 color files) - if(sh_video->bih->biCompression<=1 && sh_video->bih->biSize==40) - sh_video->bih->biSize=chunksize; - if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(sh_video->bih,MSGL_V); - 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; - sh_video->format = sh_video->bih->biCompression; - mp_set_video_codec_from_tag(sh_video); - sh_video->format = mp_video_fourcc_alias(sh_video->format); -// if(demuxer->video->id==-1) demuxer->video->id=stream_id; - // IdxFix: - idxfix_videostream=stream_id; - switch(sh_video->bih->biCompression){ - case mmioFOURCC('M', 'P', 'G', '4'): - case mmioFOURCC('m', 'p', 'g', '4'): - case mmioFOURCC('D', 'I', 'V', '1'): - idxfix_divx=3; // set index recovery mpeg4 flavour: msmpeg4v1 - mp_tmsg(MSGT_HEADER,MSGL_V,"Regenerating keyframe table for M$ mpg4v1 video.\n"); - break; - 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; // set index recovery mpeg4 flavour: msmpeg4v3 - mp_tmsg(MSGT_HEADER,MSGL_V,"Regenerating keyframe table for DIVX3 video.\n"); - break; - case mmioFOURCC('D', 'I', 'V', 'X'): - case mmioFOURCC('d', 'i', 'v', 'x'): - case mmioFOURCC('D', 'X', '5', '0'): - case mmioFOURCC('X', 'V', 'I', 'D'): - case mmioFOURCC('x', 'v', 'i', 'd'): - case mmioFOURCC('F', 'M', 'P', '4'): - case mmioFOURCC('f', 'm', 'p', '4'): - idxfix_divx=2; // set index recovery mpeg4 flavour: generic mpeg4 - mp_tmsg(MSGT_HEADER,MSGL_V,"Regenerating keyframe table for MPEG-4 video.\n"); - break; - } - } else - if(last_fccType==streamtypeAUDIO){ - unsigned wf_size = chunksize<sizeof(*sh_audio->wf)?sizeof(*sh_audio->wf):chunksize; - sh_audio->wf=calloc(wf_size,1); -// sh_audio->wf=malloc(chunksize); memset(sh_audio->wf,0,chunksize); - mp_tmsg(MSGT_HEADER,MSGL_V,"Found 'wf', %d bytes of %zu\n",chunksize,sizeof(*sh_audio->wf)); - stream_read(demuxer->stream,(char*) sh_audio->wf,chunksize); - le2me_WAVEFORMATEX(sh_audio->wf); - if (sh_audio->wf->cbSize != 0 && - wf_size < sizeof(*sh_audio->wf)+sh_audio->wf->cbSize) { - sh_audio->wf=realloc(sh_audio->wf, sizeof(*sh_audio->wf)+sh_audio->wf->cbSize); - } - sh_audio->format=sh_audio->wf->wFormatTag; - if (sh_audio->wf->wFormatTag == 0xfffe && sh_audio->wf->cbSize >= 22) - sh_audio->format = le2me_16(((WAVEFORMATEXTENSIBLE *)sh_audio->wf)->SubFormat); - if (sh_audio->format == 1 && - last_fccHandler == mmioFOURCC('A', 'x', 'a', 'n')) - sh_audio->format = last_fccHandler; - mp_set_audio_codec_from_tag(sh_audio); - sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec; - chunksize=0; - if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_audio->wf,MSGL_V); - ++priv->audio_streams; -// if(demuxer->audio->id==-1) demuxer->audio->id=stream_id; - } - break; - } - case mmioFOURCC('v', 'p', 'r', 'p'): { - VideoPropHeader *vprp = malloc(chunksize); - unsigned int i; - stream_read(demuxer->stream, (void*)vprp, chunksize); - le2me_VideoPropHeader(vprp); - chunksize -= sizeof(*vprp)-sizeof(vprp->FieldInfo); - chunksize /= sizeof(VIDEO_FIELD_DESC); - if (vprp->nbFieldPerFrame > chunksize) { - vprp->nbFieldPerFrame = chunksize; - } - chunksize = 0; - for (i=0; i<vprp->nbFieldPerFrame; i++) { - le2me_VIDEO_FIELD_DESC(&vprp->FieldInfo[i]); - } - if (sh_video) { - sh_video->aspect = GET_AVI_ASPECT(vprp->dwFrameAspectRatio); - } - if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_vprp(vprp,MSGL_V); - free(vprp); - break; - } - case mmioFOURCC('d', 'm', 'l', 'h'): { - // dmlh 00 00 00 04 frms - unsigned int total_frames = stream_read_dword_le(demuxer->stream); - mp_tmsg(MSGT_HEADER,MSGL_V,"AVI: dmlh found (size=%d) (total_frames=%d)\n", chunksize, total_frames); - stream_skip(demuxer->stream, chunksize-4); - chunksize = 0; - } - break; - case ckidAVINEWINDEX: - if(demuxer->movi_end>stream_tell(demuxer->stream)) - demuxer->movi_end=stream_tell(demuxer->stream); // fixup movi-end - if(index_mode && !priv->isodml){ - int read; - int i; - priv->idx_size=size2>>4; - mp_tmsg(MSGT_HEADER,MSGL_V,"Reading INDEX block, %d chunks for %d frames (fpos=%"PRId64").\n", - priv->idx_size,avih.dwTotalFrames, (int64_t)stream_tell(demuxer->stream)); - priv->idx=malloc(priv->idx_size<<4); -// printf("\nindex to %p !!!!! (priv=%p)\n",priv->idx,priv); - read = stream_read(demuxer->stream,(char*)priv->idx,priv->idx_size<<4); - priv->idx_size = FFMAX(read, 0) >> 4; - for (i = 0; i < priv->idx_size; i++) { // swap index to machine endian - AVIINDEXENTRY *entry=(AVIINDEXENTRY*)priv->idx + i; - le2me_AVIINDEXENTRY(entry); - /* - * We (ab)use the upper word for bits 32-47 of the offset, so - * we'll clear them here. - * FIXME: AFAIK no codec uses them, but if one does it will break - */ - entry->dwFlags&=0xffff; - } - chunksize-=priv->idx_size<<4; - if( mp_msg_test(MSGT_HEADER,MSGL_DBG2) ) print_index(priv->idx,priv->idx_size,MSGL_DBG2); - } - break; - /* added May 2002 */ - case mmioFOURCC('R','I','F','F'): { - char riff_type[4]; - - mp_tmsg(MSGT_HEADER, MSGL_V, "Additional RIFF header...\n"); - stream_read(demuxer->stream, riff_type, sizeof riff_type); - if (strncmp(riff_type, "AVIX", sizeof riff_type)) - mp_tmsg(MSGT_HEADER, MSGL_WARN, "** Warning: this is no extended AVI header..\n"); - else { - /* - * We got an extended AVI header, so we need to switch to - * ODML to get seeking to work, provided we got indx chunks - * in the header (suidx_size > 0). - */ - if (priv->suidx_size > 0) - priv->isodml = 1; - } - chunksize = 0; - list_end = 0; /* a new list will follow */ - break; } - case ckidAVIPADDING: - stream_skip(demuxer->stream, chunksize); - chunksize = 0; - break; - } - if(hdr){ - mp_msg(MSGT_HEADER,MSGL_V,"hdr=%s size=%u\n",hdr,size2); - if(size2==3) - chunksize=1; // empty - else { - 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); - demux_info_add(demuxer, hdr, buf); - } - } - mp_msg(MSGT_HEADER,MSGL_DBG2,"list_end=0x%"PRIX64" pos=0x%"PRIX64" chunksize=0x%"PRIX64" next=0x%"PRIX64"\n", - (int64_t)list_end, (int64_t)stream_tell(demuxer->stream), - (int64_t)chunksize, (int64_t)chunksize+(int64_t)stream_tell(demuxer->stream)); - if(list_end>0 && - chunksize+stream_tell(demuxer->stream) == list_end) list_end=0; - if(list_end>0 && chunksize+stream_tell(demuxer->stream)>list_end){ - mp_tmsg(MSGT_HEADER,MSGL_V,"Broken chunk? chunksize=%d (id=%.4s)\n",chunksize,(char *) &id); - stream_seek(demuxer->stream,list_end); - list_end=0; - } else - if(chunksize>0) stream_skip(demuxer->stream,chunksize); else - if((int)chunksize<0) mp_msg(MSGT_HEADER,MSGL_WARN,"chunksize=%u (id=%.4s)\n",chunksize,(char *) &id); - -} - -if (priv->suidx_size > 0 && priv->idx_size == 0) { - /* - * No NEWAVIINDEX, but we got an OpenDML index. - */ - priv->isodml = 1; -} - -if (priv->isodml && (index_mode==-1 || index_mode==0 || index_mode==1)) { - int i, j, k; - - avisuperindex_chunk *cx; - AVIINDEXENTRY *idx; - - - if (priv->idx_size) free(priv->idx); - priv->idx_size = 0; - priv->idx_offset = 0; - priv->idx = NULL; - - mp_tmsg(MSGT_HEADER, MSGL_INFO, "AVI: ODML: Building ODML index (%d superindexchunks).\n", priv->suidx_size); - - // read the standard indices - for (cx = &priv->suidx[0], i=0; i<priv->suidx_size; cx++, i++) { - for (j=0; j<cx->nEntriesInUse; j++) { - int ret1, ret2; - memset(&cx->stdidx[j], 0, 32); - ret1 = stream_seek(demuxer->stream, (int64_t)cx->aIndex[j].qwOffset); - ret2 = stream_read(demuxer->stream, (char *)&cx->stdidx[j], 32); - if (ret1 != 1 || ret2 != 32 || cx->stdidx[j].nEntriesInUse==0) { - // this is a broken file (probably incomplete) let the standard - // gen_index routine handle this - priv->isodml = 0; - priv->idx_size = 0; - mp_tmsg(MSGT_HEADER, MSGL_WARN, "AVI: ODML: Broken (incomplete?) file detected. Will use traditional index.\n"); - goto freeout; - } - - le2me_AVISTDIDXCHUNK(&cx->stdidx[j]); - print_avistdindex_chunk(&cx->stdidx[j],MSGL_V); - priv->idx_size += cx->stdidx[j].nEntriesInUse; - cx->stdidx[j].aIndex = malloc(cx->stdidx[j].nEntriesInUse*sizeof(avistdindex_entry)); - stream_read(demuxer->stream, (char *)cx->stdidx[j].aIndex, - cx->stdidx[j].nEntriesInUse*sizeof(avistdindex_entry)); - for (k=0;k<cx->stdidx[j].nEntriesInUse; k++) - le2me_AVISTDIDXENTRY(&cx->stdidx[j].aIndex[k]); - - cx->stdidx[j].dwReserved3 = 0; - - } - } - - /* - * We convert the index by translating all entries into AVIINDEXENTRYs - * and sorting them by offset. The result should be the same index - * we would get with -forceidx. - */ - - idx = priv->idx = malloc(priv->idx_size * sizeof (AVIINDEXENTRY)); - - for (cx = priv->suidx; cx != &priv->suidx[priv->suidx_size]; cx++) { - avistdindex_chunk *sic; - for (sic = cx->stdidx; sic != &cx->stdidx[cx->nEntriesInUse]; sic++) { - avistdindex_entry *sie; - for (sie = sic->aIndex; sie != &sic->aIndex[sic->nEntriesInUse]; sie++) { - uint64_t off = sic->qwBaseOffset + sie->dwOffset - 8; - memcpy(&idx->ckid, sic->dwChunkId, 4); - idx->dwChunkOffset = off; - idx->dwFlags = (off >> 32) << 16; - idx->dwChunkLength = sie->dwSize & 0x7fffffff; - idx->dwFlags |= (sie->dwSize&0x80000000)?0x0:AVIIF_KEYFRAME; // bit 31 denotes !keyframe - idx++; - } - } - } - qsort(priv->idx, priv->idx_size, sizeof(AVIINDEXENTRY), avi_idx_cmp); - - /* - Hack to work around a "wrong" index in some divx odml files - (processor_burning.avi as an example) - They have ##dc on non keyframes but the ix00 tells us they are ##db. - Read the fcc of a non-keyframe vid frame and check it. - */ - - { - uint32_t id; - uint32_t db = 0; - - // find out the video stream id. I have seen files with 01db. - for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){ - unsigned char res[2]; - if (odml_get_vstream_id(idx->ckid, res)) { - db = mmioFOURCC(res[0], res[1], 'd', 'b'); - break; - } - } - - // find first non keyframe - for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){ - if (!(idx->dwFlags & AVIIF_KEYFRAME) && idx->ckid == db) break; - } - if (i<priv->idx_size && db) { - stream_seek(demuxer->stream, AVI_IDX_OFFSET(idx)); - id = stream_read_dword_le(demuxer->stream); - if (id && id != db) // index fcc and real fcc differ? fix it. - for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){ - if (!(idx->dwFlags & AVIIF_KEYFRAME) && idx->ckid == db) - idx->ckid = id; - } - } - } - - if ( mp_msg_test(MSGT_HEADER,MSGL_DBG2) ) print_index(priv->idx, priv->idx_size,MSGL_DBG2); - - demuxer->movi_end=demuxer->stream->end_pos; - -freeout: - - // free unneeded stuff - cx = &priv->suidx[0]; - do { - for (j=0;j<cx->nEntriesInUse;j++) - if (cx->stdidx[j].nEntriesInUse) free(cx->stdidx[j].aIndex); - free(cx->stdidx); - - } while (cx++ != &priv->suidx[priv->suidx_size-1]); - free(priv->suidx); - -} - -if(index_mode>=2 || (priv->idx_size==0 && index_mode==1)){ - int idx_pos = 0; - // build index for file: - stream_seek(demuxer->stream,demuxer->movi_start); - - priv->idx_size=0; - priv->idx=NULL; - - while(1){ - int id; - unsigned len; - int64_t skip; - AVIINDEXENTRY* idx; - unsigned int c; - demuxer->filepos=stream_tell(demuxer->stream); - if(demuxer->filepos>=demuxer->movi_end && demuxer->movi_start<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==mmioFOURCC('R', 'I', 'F', 'F')){ - id=stream_read_dword_le(demuxer->stream); // list or RIFF type - continue; - } - if(stream_eof(demuxer->stream)) break; - if(!id || avi_stream_id(id)==100) goto skip_chunk; // bad ID (or padding?) - - if(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){idx_pos=0; break;} // error! - } - idx=&((AVIINDEXENTRY *)priv->idx)[idx_pos++]; - idx->ckid=id; - idx->dwFlags=AVIIF_KEYFRAME; // FIXME - idx->dwFlags|=(demuxer->filepos>>16)&0xffff0000U; - idx->dwChunkOffset=(unsigned long)demuxer->filepos; - idx->dwChunkLength=len; - - c=stream_read_dword(demuxer->stream); - - if(!len) idx->dwFlags&=~AVIIF_KEYFRAME; - - // Fix keyframes for DivX files: - if(idxfix_divx) - if(avi_stream_id(id)==idxfix_videostream){ - switch(idxfix_divx){ - case 3: c=stream_read_dword(demuxer->stream)<<5; //skip 32+5 bits for m$mpeg4v1 - case 1: if(c&0x40000000) idx->dwFlags&=~AVIIF_KEYFRAME;break; // divx 3 - case 2: if(c==0x1B6) idx->dwFlags&=~AVIIF_KEYFRAME;break; // divx 4 - } - } - - // update status line: - { static int64_t lastpos; - int64_t pos; - int64_t len=demuxer->movi_end-demuxer->movi_start; - if(len){ - pos=100*(demuxer->filepos-demuxer->movi_start)/len; // % - } else { - pos=(demuxer->filepos-demuxer->movi_start)>>20; // MB - } - if(pos!=lastpos){ - lastpos=pos; - mp_tmsg(MSGT_HEADER,MSGL_STATUS, "Generating Index: %3lu %s \r", - (unsigned long)pos, len?"%":"MB"); - } - } - mp_dbg(MSGT_HEADER,MSGL_DBG2,"%08X %08X %.4s %08X %X\n",(unsigned int)demuxer->filepos,id,(char *) &id,(int)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)&(~1UL); // total bytes in this chunk - stream_seek(demuxer->stream,8+demuxer->filepos+skip); - } - priv->idx_size=idx_pos; - mp_tmsg(MSGT_HEADER,MSGL_INFO,"AVI: Generated index table for %d chunks!\n",priv->idx_size); - if( mp_msg_test(MSGT_HEADER,MSGL_DBG2) ) print_index(priv->idx,priv->idx_size,MSGL_DBG2); - -} -} diff --git a/demux/aviheader.h b/demux/aviheader.h deleted file mode 100644 index 0d721908d3..0000000000 --- a/demux/aviheader.h +++ /dev/null @@ -1,382 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_AVIHEADER_H -#define MPLAYER_AVIHEADER_H - -#include <sys/types.h> -#include <stdint.h> -#include "config.h" -#include "libavutil/common.h" -#include "compat/mpbswap.h" - -#ifndef mmioFOURCC -#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \ - ( (uint32_t)(uint8_t)(ch0) | ( (uint32_t)(uint8_t)(ch1) << 8 ) | \ - ( (uint32_t)(uint8_t)(ch2) << 16 ) | ( (uint32_t)(uint8_t)(ch3) << 24 ) ) -#endif - -/* Macro to make a TWOCC out of two characters */ -#ifndef aviTWOCC -#define aviTWOCC(ch0, ch1) ((uint16_t)(uint8_t)(ch0) | ((uint16_t)(uint8_t)(ch1) << 8)) -#endif - -//typedef uint16_t TWOCC; -//typedef uint32_t FOURCC; - -/* form types, list types, and chunk types */ -#define formtypeAVI mmioFOURCC('A', 'V', 'I', ' ') -#define listtypeAVIHEADER mmioFOURCC('h', 'd', 'r', 'l') -#define ckidAVIMAINHDR mmioFOURCC('a', 'v', 'i', 'h') -#define listtypeSTREAMHEADER mmioFOURCC('s', 't', 'r', 'l') -#define ckidSTREAMHEADER mmioFOURCC('s', 't', 'r', 'h') -#define ckidSTREAMFORMAT mmioFOURCC('s', 't', 'r', 'f') -#define ckidSTREAMHANDLERDATA mmioFOURCC('s', 't', 'r', 'd') -#define ckidSTREAMNAME mmioFOURCC('s', 't', 'r', 'n') - -#define listtypeAVIMOVIE mmioFOURCC('m', 'o', 'v', 'i') -#define listtypeAVIRECORD mmioFOURCC('r', 'e', 'c', ' ') - -#define ckidAVINEWINDEX mmioFOURCC('i', 'd', 'x', '1') - -/* -** Stream types for the <fccType> field of the stream header. -*/ -#define streamtypeVIDEO mmioFOURCC('v', 'i', 'd', 's') -#define streamtypeAUDIO mmioFOURCC('a', 'u', 'd', 's') -#define streamtypeMIDI mmioFOURCC('m', 'i', 'd', 's') -#define streamtypeTEXT mmioFOURCC('t', 'x', 't', 's') - -/* Basic chunk types */ -#define cktypeDIBbits aviTWOCC('d', 'b') -#define cktypeDIBcompressed aviTWOCC('d', 'c') -#define cktypePALchange aviTWOCC('p', 'c') -#define cktypeWAVEbytes aviTWOCC('w', 'b') - -/* Chunk id to use for extra chunks for padding. */ -#define ckidAVIPADDING mmioFOURCC('J', 'U', 'N', 'K') - -/* flags for use in <dwFlags> in AVIFileHdr */ -#define AVIF_HASINDEX 0x00000010 // Index at end of file? -#define AVIF_MUSTUSEINDEX 0x00000020 -#define AVIF_ISINTERLEAVED 0x00000100 -#define AVIF_TRUSTCKTYPE 0x00000800 // Use CKType to find key frames? -#define AVIF_WASCAPTUREFILE 0x00010000 -#define AVIF_COPYRIGHTED 0x00020000 - -typedef struct -{ - uint32_t dwMicroSecPerFrame; // frame display rate (or 0L) - uint32_t dwMaxBytesPerSec; // max. transfer rate - uint32_t dwPaddingGranularity; // pad to multiples of this - // size; normally 2K. - uint32_t dwFlags; // the ever-present flags - uint32_t dwTotalFrames; // # frames in file - uint32_t dwInitialFrames; - uint32_t dwStreams; - uint32_t dwSuggestedBufferSize; - - uint32_t dwWidth; - uint32_t dwHeight; - - uint32_t dwReserved[4]; -} MainAVIHeader; - -typedef struct rectangle_t { - short left; - short top; - short right; - short bottom; -} rectangle_t; - -typedef struct { - uint32_t fccType; - uint32_t fccHandler; - uint32_t dwFlags; /* Contains AVITF_* flags */ - uint16_t wPriority; - uint16_t wLanguage; - uint32_t dwInitialFrames; - uint32_t dwScale; - uint32_t dwRate; /* dwRate / dwScale == samples/second */ - uint32_t dwStart; - uint32_t dwLength; /* In units above... */ - uint32_t dwSuggestedBufferSize; - uint32_t dwQuality; - uint32_t dwSampleSize; - rectangle_t rcFrame; -} AVIStreamHeader; - -/* Flags for index */ -#define AVIIF_LIST 0x00000001L // chunk is a 'LIST' -#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame. - -#define AVIIF_NOTIME 0x00000100L // this frame doesn't take any time -#define AVIIF_COMPUSE 0x0FFF0000L // these bits are for compressor use - -#ifndef FOURCC_RIFF -#define FOURCC_RIFF mmioFOURCC('R', 'I', 'F', 'F') -#define FOURCC_LIST mmioFOURCC('L', 'I', 'S', 'T') -#endif - -typedef struct -{ - uint32_t ckid; - uint32_t dwFlags; - uint32_t dwChunkOffset; // Position of chunk - uint32_t dwChunkLength; // Length of chunk -} AVIINDEXENTRY; - - -typedef struct avisuperindex_entry { - uint64_t qwOffset; // absolute file offset - uint32_t dwSize; // size of index chunk at this offset - uint32_t dwDuration; // time span in stream ticks -} avisuperindex_entry; - -typedef struct avistdindex_entry { - uint32_t dwOffset; // qwBaseOffset + this is absolute file offset - uint32_t dwSize; // bit 31 is set if this is NOT a keyframe -} avistdindex_entry; - -// Standard index -typedef struct __attribute__((packed)) avistdindex_chunk { - char fcc[4]; // ix## - uint32_t dwSize; // size of this chunk - uint16_t wLongsPerEntry; // must be sizeof(aIndex[0])/sizeof(DWORD) - uint8_t bIndexSubType; // must be 0 - uint8_t bIndexType; // must be AVI_INDEX_OF_CHUNKS - uint32_t nEntriesInUse; // first unused entry - char dwChunkId[4]; // '##dc' or '##db' or '##wb' etc.. - uint64_t qwBaseOffset; // all dwOffsets in aIndex array are relative to this - uint32_t dwReserved3; // must be 0 - avistdindex_entry *aIndex; // the actual frames -} avistdindex_chunk; - - -// Base Index Form 'indx' -typedef struct avisuperindex_chunk { - char fcc[4]; - uint32_t dwSize; // size of this chunk - uint16_t wLongsPerEntry; // size of each entry in aIndex array (must be 4*4 for us) - uint8_t bIndexSubType; // future use. must be 0 - uint8_t bIndexType; // one of AVI_INDEX_* codes - uint32_t nEntriesInUse; // index of first unused member in aIndex array - char dwChunkId[4]; // fcc of what is indexed - uint32_t dwReserved[3]; // meaning differs for each index type/subtype. - // 0 if unused - avisuperindex_entry *aIndex; // position of ix## chunks - avistdindex_chunk *stdidx; // the actual std indices -} avisuperindex_chunk; - -typedef struct { - uint32_t CompressedBMHeight; - uint32_t CompressedBMWidth; - uint32_t ValidBMHeight; - uint32_t ValidBMWidth; - uint32_t ValidBMXOffset; - uint32_t ValidBMYOffset; - uint32_t VideoXOffsetInT; - uint32_t VideoYValidStartLine; -} VIDEO_FIELD_DESC; - -typedef struct { - uint32_t VideoFormatToken; - uint32_t VideoStandard; - uint32_t dwVerticalRefreshRate; - uint32_t dwHTotalInT; - uint32_t dwVTotalInLines; - uint32_t dwFrameAspectRatio; - uint32_t dwFrameWidthInPixels; - uint32_t dwFrameHeightInLines; - uint32_t nbFieldPerFrame; - VIDEO_FIELD_DESC FieldInfo[2]; -} VideoPropHeader; - -typedef enum { - FORMAT_UNKNOWN, - FORMAT_PAL_SQUARE, - FORMAT_PAL_CCIR_601, - FORMAT_NTSC_SQUARE, - FORMAT_NTSC_CCIR_601, -} VIDEO_FORMAT; - -typedef enum { - STANDARD_UNKNOWN, - STANDARD_PAL, - STANDARD_NTSC, - STANDARD_SECAM -} VIDEO_STANDARD; - -#define MAKE_AVI_ASPECT(a, b) (((a)<<16)|(b)) -#define GET_AVI_ASPECT(a) ((float)((a)>>16)/(float)((a)&0xffff)) - -/* - * Some macros to swap little endian structures read from an AVI file - * into machine endian format - */ -#if BYTE_ORDER == BIG_ENDIAN -#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); \ -} -#define le2me_AVISTDIDXCHUNK(h) {\ - char c; \ - c = (h)->fcc[0]; (h)->fcc[0] = (h)->fcc[3]; (h)->fcc[3] = c; \ - c = (h)->fcc[1]; (h)->fcc[1] = (h)->fcc[2]; (h)->fcc[2] = c; \ - (h)->dwSize = le2me_32((h)->dwSize); \ - (h)->wLongsPerEntry = le2me_16((h)->wLongsPerEntry); \ - (h)->nEntriesInUse = le2me_32((h)->nEntriesInUse); \ - c = (h)->dwChunkId[0]; (h)->dwChunkId[0] = (h)->dwChunkId[3]; (h)->dwChunkId[3] = c; \ - c = (h)->dwChunkId[1]; (h)->dwChunkId[1] = (h)->dwChunkId[2]; (h)->dwChunkId[2] = c; \ - (h)->qwBaseOffset = le2me_64((h)->qwBaseOffset); \ - (h)->dwReserved3 = le2me_32((h)->dwReserved3); \ -} -#define le2me_AVISTDIDXENTRY(h) {\ - (h)->dwOffset = le2me_32((h)->dwOffset); \ - (h)->dwSize = le2me_32((h)->dwSize); \ -} -#define le2me_VideoPropHeader(h) { \ - (h)->VideoFormatToken = le2me_32((h)->VideoFormatToken); \ - (h)->VideoStandard = le2me_32((h)->VideoStandard); \ - (h)->dwVerticalRefreshRate = le2me_32((h)->dwVerticalRefreshRate); \ - (h)->dwHTotalInT = le2me_32((h)->dwHTotalInT); \ - (h)->dwVTotalInLines = le2me_32((h)->dwVTotalInLines); \ - (h)->dwFrameAspectRatio = le2me_32((h)->dwFrameAspectRatio); \ - (h)->dwFrameWidthInPixels = le2me_32((h)->dwFrameWidthInPixels); \ - (h)->dwFrameHeightInLines = le2me_32((h)->dwFrameHeightInLines); \ - (h)->nbFieldPerFrame = le2me_32((h)->nbFieldPerFrame); \ -} -#define le2me_VIDEO_FIELD_DESC(h) { \ - (h)->CompressedBMHeight = le2me_32((h)->CompressedBMHeight); \ - (h)->CompressedBMWidth = le2me_32((h)->CompressedBMWidth); \ - (h)->ValidBMHeight = le2me_32((h)->ValidBMHeight); \ - (h)->ValidBMWidth = le2me_32((h)->ValidBMWidth); \ - (h)->ValidBMXOffset = le2me_32((h)->ValidBMXOffset); \ - (h)->ValidBMYOffset = le2me_32((h)->ValidBMYOffset); \ - (h)->VideoXOffsetInT = le2me_32((h)->VideoXOffsetInT); \ - (h)->VideoYValidStartLine = le2me_32((h)->VideoYValidStartLine); \ -} - -#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) /**/ -#define le2me_AVISTDIDXCHUNK(h) /**/ -#define le2me_AVISTDIDXENTRY(h) /**/ -#define le2me_VideoPropHeader(h) /**/ -#define le2me_VIDEO_FIELD_DESC(h) /**/ -#endif - -typedef struct { - // index stuff: - void* idx; - int idx_size; - int64_t idx_pos; - int64_t idx_pos_a; - int64_t idx_pos_v; - int64_t idx_offset; // ennyit kell hozzaadni az index offset ertekekhez - // bps-based PTS stuff: - int video_pack_no; - int audio_block_size; - int64_t audio_block_no; - // interleaved PTS stuff: - int skip_video_frames; - int audio_streams; - 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; - unsigned int numberofframes; - avisuperindex_chunk *suidx; - int suidx_size; - int isodml; - int warned_unaligned; -} avi_priv_t; - -#define AVI_PRIV ((avi_priv_t*)(demuxer->priv)) - -#define AVI_IDX_OFFSET(x) ((((uint64_t)(x)->dwFlags&0xffff0000)<<16)+(x)->dwChunkOffset) - -struct demuxer; -void read_avi_header(struct demuxer *demuxer, int index_mode); - -#endif /* MPLAYER_AVIHEADER_H */ diff --git a/demux/aviprint.c b/demux/aviprint.c deleted file mode 100644 index 5d285c2104..0000000000 --- a/demux/aviprint.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <inttypes.h> - -#include "config.h" - -// for avi_stream_id(): -#include "stream/stream.h" -#include "demux.h" - -#include "aviheader.h" -#include "ms_hdr.h" -#include "aviprint.h" - -//#include "codec-cfg.h" -//#include "stheader.h" - -void print_avih_flags(MainAVIHeader *h, int verbose_level){ - mp_msg(MSGT_HEADER, verbose_level, "MainAVIHeader.dwFlags: (%"PRId32")%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, int verbose_level){ - mp_msg(MSGT_HEADER, verbose_level, "======= AVI Header =======\n"); - mp_msg(MSGT_HEADER, verbose_level, "us/frame: %"PRId32" (fps=%5.3f)\n",h->dwMicroSecPerFrame,1000000.0f/(float)h->dwMicroSecPerFrame); - mp_msg(MSGT_HEADER, verbose_level, "max bytes/sec: %"PRId32"\n",h->dwMaxBytesPerSec); - mp_msg(MSGT_HEADER, verbose_level, "padding: %"PRId32"\n",h->dwPaddingGranularity); - print_avih_flags(h, verbose_level); - mp_msg(MSGT_HEADER, verbose_level, "frames total: %"PRId32" initial: %"PRId32"\n",h->dwTotalFrames,h->dwInitialFrames); - mp_msg(MSGT_HEADER, verbose_level, "streams: %"PRId32"\n",h->dwStreams); - mp_msg(MSGT_HEADER, verbose_level, "Suggested BufferSize: %"PRId32"\n",h->dwSuggestedBufferSize); - mp_msg(MSGT_HEADER, verbose_level, "Size: %"PRId32" x %"PRId32"\n",h->dwWidth,h->dwHeight); - mp_msg(MSGT_HEADER, verbose_level, "==========================\n"); -} - -void print_strh(AVIStreamHeader *h, int verbose_level){ - mp_msg(MSGT_HEADER, verbose_level, "====== STREAM Header =====\n"); - mp_msg(MSGT_HEADER, verbose_level, "Type: %.4s FCC: %.4s (%X)\n",(char *)&h->fccType,(char *)&h->fccHandler,(unsigned int)h->fccHandler); - mp_msg(MSGT_HEADER, verbose_level, "Flags: %"PRId32"\n",h->dwFlags); - mp_msg(MSGT_HEADER, verbose_level, "Priority: %d Language: %d\n",h->wPriority,h->wLanguage); - mp_msg(MSGT_HEADER, verbose_level, "InitialFrames: %"PRId32"\n",h->dwInitialFrames); - mp_msg(MSGT_HEADER, verbose_level, "Rate: %"PRId32"/%"PRId32" = %5.3f\n",h->dwRate,h->dwScale,(float)h->dwRate/(float)h->dwScale); - mp_msg(MSGT_HEADER, verbose_level, "Start: %"PRId32" Len: %"PRId32"\n",h->dwStart,h->dwLength); - mp_msg(MSGT_HEADER, verbose_level, "Suggested BufferSize: %"PRId32"\n",h->dwSuggestedBufferSize); - mp_msg(MSGT_HEADER, verbose_level, "Quality %"PRId32"\n",h->dwQuality); - mp_msg(MSGT_HEADER, verbose_level, "Sample size: %"PRId32"\n",h->dwSampleSize); - mp_msg(MSGT_HEADER, verbose_level, "==========================\n"); -} - -void print_wave_header(WAVEFORMATEX *h, int verbose_level){ - mp_msg(MSGT_HEADER, verbose_level, "======= WAVE Format =======\n"); - mp_msg(MSGT_HEADER, verbose_level, "Format Tag: %d (0x%X)\n",h->wFormatTag,h->wFormatTag); - mp_msg(MSGT_HEADER, verbose_level, "Channels: %d\n",h->nChannels); - mp_msg(MSGT_HEADER, verbose_level, "Samplerate: %"PRId32"\n",h->nSamplesPerSec); - mp_msg(MSGT_HEADER, verbose_level, "avg byte/sec: %"PRId32"\n",h->nAvgBytesPerSec); - mp_msg(MSGT_HEADER, verbose_level, "Block align: %d\n",h->nBlockAlign); - mp_msg(MSGT_HEADER, verbose_level, "bits/sample: %d\n",h->wBitsPerSample); - mp_msg(MSGT_HEADER, verbose_level, "cbSize: %d\n",h->cbSize); - if(h->wFormatTag==0x55 && h->cbSize>=12){ - MPEGLAYER3WAVEFORMAT* h2=(MPEGLAYER3WAVEFORMAT *)h; - mp_msg(MSGT_HEADER, verbose_level, "mp3.wID=%d\n",h2->wID); - mp_msg(MSGT_HEADER, verbose_level, "mp3.fdwFlags=0x%"PRIX32"\n",h2->fdwFlags); - mp_msg(MSGT_HEADER, verbose_level, "mp3.nBlockSize=%d\n",h2->nBlockSize); - mp_msg(MSGT_HEADER, verbose_level, "mp3.nFramesPerBlock=%d\n",h2->nFramesPerBlock); - mp_msg(MSGT_HEADER, verbose_level, "mp3.nCodecDelay=%d\n",h2->nCodecDelay); - } - else if (h->wFormatTag == 0xfffe && h->cbSize >= 22) { - WAVEFORMATEXTENSIBLE *h2 = (WAVEFORMATEXTENSIBLE *)h; - mp_msg(MSGT_HEADER, verbose_level, "ex.wValidBitsPerSample=%d\n", h2->wValidBitsPerSample); - mp_msg(MSGT_HEADER, verbose_level, "ex.dwChannelMask=0x%X\n", h2->dwChannelMask); - mp_msg(MSGT_HEADER, verbose_level, "ex.SubFormat=%d (0x%X)\n", h2->SubFormat, h2->SubFormat); - } - else if (h->cbSize > 0) - { - int i; - uint8_t* p = (uint8_t*)(h + 1); - mp_msg(MSGT_HEADER, verbose_level, "Unknown extra header dump: "); - for (i = 0; i < h->cbSize; i++) - mp_msg(MSGT_HEADER, verbose_level, "[%x] ", p[i]); - mp_msg(MSGT_HEADER, verbose_level, "\n"); - } - mp_msg(MSGT_HEADER, verbose_level, "==========================================================================\n"); -} - - -void print_video_header(BITMAPINFOHEADER *h, int verbose_level){ - mp_msg(MSGT_HEADER, verbose_level, "======= VIDEO Format ======\n"); - mp_msg(MSGT_HEADER, verbose_level, " biSize %d\n", h->biSize); - mp_msg(MSGT_HEADER, verbose_level, " biWidth %d\n", h->biWidth); - mp_msg(MSGT_HEADER, verbose_level, " biHeight %d\n", h->biHeight); - mp_msg(MSGT_HEADER, verbose_level, " biPlanes %d\n", h->biPlanes); - mp_msg(MSGT_HEADER, verbose_level, " biBitCount %d\n", h->biBitCount); - mp_msg(MSGT_HEADER, verbose_level, " biCompression %d='%.4s'\n", h->biCompression, (char *)&h->biCompression); - mp_msg(MSGT_HEADER, verbose_level, " biSizeImage %d\n", h->biSizeImage); - if (h->biSize > sizeof(*h)) - { - int i; - uint8_t* p = (uint8_t*)(h + 1); - mp_msg(MSGT_HEADER, verbose_level, "Unknown extra header dump: "); - for (i = 0; i < h->biSize-sizeof(*h); i++) - mp_msg(MSGT_HEADER, verbose_level, "[%x] ", *(p+i)); - mp_msg(MSGT_HEADER, verbose_level, "\n"); - } - mp_msg(MSGT_HEADER, verbose_level, "===========================\n"); -} - -void print_vprp(VideoPropHeader *vprp, int verbose_level){ - int i; - mp_msg(MSGT_HEADER, verbose_level, "======= Video Properties Header =======\n"); - mp_msg(MSGT_HEADER, verbose_level, "Format: %d VideoStandard: %d\n", - vprp->VideoFormatToken,vprp->VideoStandard); - mp_msg(MSGT_HEADER, verbose_level, "VRefresh: %d HTotal: %d VTotal: %d\n", - vprp->dwVerticalRefreshRate, vprp->dwHTotalInT, vprp->dwVTotalInLines); - mp_msg(MSGT_HEADER, verbose_level, "FrameAspect: %d:%d Framewidth: %d Frameheight: %d\n", - vprp->dwFrameAspectRatio >> 16, vprp->dwFrameAspectRatio & 0xffff, - vprp->dwFrameWidthInPixels, vprp->dwFrameHeightInLines); - mp_msg(MSGT_HEADER, verbose_level, "Fields: %d\n", vprp->nbFieldPerFrame); - for (i=0; i<vprp->nbFieldPerFrame; i++) { - VIDEO_FIELD_DESC *vfd = &vprp->FieldInfo[i]; - mp_msg(MSGT_HEADER, verbose_level, " == Field %d description ==\n", i); - mp_msg(MSGT_HEADER, verbose_level, " CompressedBMHeight: %d CompressedBMWidth: %d\n", - vfd->CompressedBMHeight, vfd->CompressedBMWidth); - mp_msg(MSGT_HEADER, verbose_level, " ValidBMHeight: %d ValidBMWidth: %d\n", - vfd->ValidBMHeight, vfd->ValidBMWidth); - mp_msg(MSGT_HEADER, verbose_level, " ValidBMXOffset: %d ValidBMYOffset: %d\n", - vfd->ValidBMXOffset, vfd->ValidBMYOffset); - mp_msg(MSGT_HEADER, verbose_level, " VideoXOffsetInT: %d VideoYValidStartLine: %d\n", - vfd->VideoXOffsetInT, vfd->VideoYValidStartLine); - } - mp_msg(MSGT_HEADER, verbose_level, "=======================================\n"); -} - -void print_index(AVIINDEXENTRY *idx, int idx_size, int verbose_level){ - int i; - unsigned int pos[256]; - unsigned int num[256]; - memset(pos, 0, sizeof(pos)); - memset(num, 0, sizeof(num)); - for(i=0;i<idx_size;i++){ - int id=avi_stream_id(idx[i].ckid); - if(id<0 || id>255) id=255; - mp_msg(MSGT_HEADER, verbose_level, "%5d: %.4s %4X %016"PRIX64" len:%6"PRId32" pos:%7d->%7.3f %7d->%7.3f\n",i, - (char *)&idx[i].ckid, - (unsigned int)idx[i].dwFlags&0xffff, - (uint64_t)AVI_IDX_OFFSET(&idx[i]), -// 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]; - } -} - -void print_avistdindex_chunk(avistdindex_chunk *h, int verbose_level){ - mp_msg (MSGT_HEADER, verbose_level, "====== AVI Standard Index Header ========\n"); - mp_msg (MSGT_HEADER, verbose_level, " FCC (%.4s) dwSize (%d) wLongsPerEntry(%d)\n", h->fcc, h->dwSize, h->wLongsPerEntry); - mp_msg (MSGT_HEADER, verbose_level, " bIndexSubType (%d) bIndexType (%d)\n", h->bIndexSubType, h->bIndexType); - mp_msg (MSGT_HEADER, verbose_level, " nEntriesInUse (%d) dwChunkId (%.4s)\n", h->nEntriesInUse, h->dwChunkId); - mp_msg (MSGT_HEADER, verbose_level, " qwBaseOffset (0x%"PRIX64") dwReserved3 (%d)\n", h->qwBaseOffset, h->dwReserved3); - mp_msg (MSGT_HEADER, verbose_level, "===========================\n"); -} -void print_avisuperindex_chunk(avisuperindex_chunk *h, int verbose_level){ - mp_msg (MSGT_HEADER, verbose_level, "====== AVI Super Index Header ========\n"); - mp_msg (MSGT_HEADER, verbose_level, " FCC (%.4s) dwSize (%d) wLongsPerEntry(%d)\n", h->fcc, h->dwSize, h->wLongsPerEntry); - mp_msg (MSGT_HEADER, verbose_level, " bIndexSubType (%d) bIndexType (%d)\n", h->bIndexSubType, h->bIndexType); - mp_msg (MSGT_HEADER, verbose_level, " nEntriesInUse (%d) dwChunkId (%.4s)\n", h->nEntriesInUse, h->dwChunkId); - mp_msg (MSGT_HEADER, verbose_level, " dwReserved[0] (%d) dwReserved[1] (%d) dwReserved[2] (%d)\n", - h->dwReserved[0], h->dwReserved[1], h->dwReserved[2]); - mp_msg (MSGT_HEADER, verbose_level, "===========================\n"); -} diff --git a/demux/aviprint.h b/demux/aviprint.h deleted file mode 100644 index 86123b7725..0000000000 --- a/demux/aviprint.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_AVIPRINT_H -#define MPLAYER_AVIPRINT_H - -#include "ms_hdr.h" -#include "aviheader.h" - -void print_avih_flags(MainAVIHeader *h, int verbose_level); -void print_avih(MainAVIHeader *h, int verbose_level); -void print_strh(AVIStreamHeader *h, int verbose_level); -void print_wave_header(WAVEFORMATEX *h, int verbose_level); -void print_video_header(BITMAPINFOHEADER *h, int verbose_level); -void print_vprp(VideoPropHeader *vprp, int verbose_level); -void print_index(AVIINDEXENTRY *idx, int idx_size, int verbose_level); -void print_avistdindex_chunk(avistdindex_chunk *h, int verbose_level); -void print_avisuperindex_chunk(avisuperindex_chunk *h, int verbose_level); - -#endif /* MPLAYER_AVIPRINT_H */ diff --git a/demux/demux.c b/demux/demux.c index a5d3211b0a..3f5851e5b6 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -55,18 +55,9 @@ extern const demuxer_desc_t demuxer_desc_rawaudio; extern const demuxer_desc_t demuxer_desc_rawvideo; extern const demuxer_desc_t demuxer_desc_tv; extern const demuxer_desc_t demuxer_desc_mf; -extern const demuxer_desc_t demuxer_desc_avi; -extern const demuxer_desc_t demuxer_desc_asf; extern const demuxer_desc_t demuxer_desc_matroska; extern const demuxer_desc_t demuxer_desc_lavf; extern const demuxer_desc_t demuxer_desc_mng; -extern const demuxer_desc_t demuxer_desc_mpeg_ps; -extern const demuxer_desc_t demuxer_desc_mpeg_pes; -extern const demuxer_desc_t demuxer_desc_mpeg_gxf; -extern const demuxer_desc_t demuxer_desc_mpeg_es; -extern const demuxer_desc_t demuxer_desc_mpeg4_es; -extern const demuxer_desc_t demuxer_desc_h264_es; -extern const demuxer_desc_t demuxer_desc_mpeg_ts; extern const demuxer_desc_t demuxer_desc_libass; extern const demuxer_desc_t demuxer_desc_subreader; @@ -86,18 +77,9 @@ const demuxer_desc_t *const demuxer_list[] = { &demuxer_desc_matroska, &demuxer_desc_lavf, &demuxer_desc_subreader, - &demuxer_desc_avi, - &demuxer_desc_asf, #ifdef CONFIG_MNG &demuxer_desc_mng, #endif - &demuxer_desc_mpeg_ps, - &demuxer_desc_mpeg_pes, - &demuxer_desc_mpeg_gxf, - &demuxer_desc_mpeg_es, - &demuxer_desc_mpeg4_es, - &demuxer_desc_h264_es, - &demuxer_desc_mpeg_ts, // auto-probe last, because it checks file-extensions only &demuxer_desc_mf, /* Please do not add any new demuxers here. If you want to implement a new @@ -234,7 +216,6 @@ static struct demux_stream *new_demuxer_stream(struct demuxer *demuxer, .stream_type = type, .id = id, .demuxer = demuxer, - .asf_seq = -1, }; return ds; } @@ -357,34 +338,6 @@ static void free_sh_stream(struct sh_stream *sh) { } -sh_sub_t *new_sh_sub_sid(demuxer_t *demuxer, int id, int sid) -{ - if (id > MAX_S_STREAMS - 1 || id < 0) { - mp_msg(MSGT_DEMUXER, MSGL_WARN, - "Requested sub stream id overflow (%d > %d)\n", id, - MAX_S_STREAMS); - return NULL; - } - if (demuxer->s_streams[id]) - mp_msg(MSGT_DEMUXER, MSGL_WARN, "Sub stream %i redefined\n", id); - else { - new_sh_stream_id(demuxer, STREAM_SUB, id, sid); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SUBTITLE_ID=%d\n", sid); - } - return demuxer->s_streams[id]; -} - -struct sh_sub *new_sh_sub_sid_lang(struct demuxer *demuxer, int id, int sid, - const char *lang) -{ - struct sh_sub *sh = new_sh_sub_sid(demuxer, id, sid); - if (lang && lang[0] && strcmp(lang, "und")) { - sh->gsh->lang = talloc_strdup(sh, lang); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_LANG=%s\n", sid, lang); - } - return sh; -} - static void free_sh_sub(sh_sub_t *sh) { mp_msg(MSGT_DEMUXER, MSGL_DBG2, "DEMUXER: freeing sh_sub at %p\n", sh); @@ -610,9 +563,7 @@ static bool demux_check_queue_full(demuxer_t *demux) "packet queue (video: %d packets in %d bytes, audio: %d " "packets in %d bytes).\n", vpacks, vbytes, apacks, abytes); mp_tmsg(MSGT_DEMUXER, MSGL_HINT, "Maybe you are playing a non-" - "interleaved stream/file or the codec failed?\nFor AVI files, " - "try to force non-interleaved mode with the " - "--demuxer=avi --avi-ni options.\n"); + "interleaved stream/file or the codec failed?\n"); } demux->warned_queue_overflow = true; @@ -716,65 +667,6 @@ int ds_fill_buffer(demux_stream_t *ds) 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; -} - -/** - * \brief read data until the given 3-byte pattern is encountered, up to maxlen - * \param mem memory to read data into, may be NULL to discard data - * \param maxlen maximum number of bytes to read - * \param read number of bytes actually read - * \param pattern pattern to search for (lowest 8 bits are ignored) - * \return whether pattern was found - */ -int demux_pattern_3(demux_stream_t *ds, unsigned char *mem, int maxlen, - int *read, uint32_t pattern) -{ - register uint32_t head = 0xffffff00; - register uint32_t pat = pattern & 0xffffff00; - int total_len = 0; - do { - register unsigned char *ds_buf = &ds->buffer[ds->buffer_size]; - int len = ds->buffer_size - ds->buffer_pos; - register long pos = -len; - if (unlikely(pos >= 0)) { // buffer is empty - ds_fill_buffer(ds); - continue; - } - do { - head |= ds_buf[pos]; - head <<= 8; - } while (++pos && head != pat); - len += pos; - if (total_len + len > maxlen) - len = maxlen - total_len; - len = demux_read_data(ds, mem ? &mem[total_len] : NULL, len); - total_len += len; - } while ((head != pat || total_len < 3) && total_len < maxlen && !ds->eof); - if (read) - *read = total_len; - return total_len >= 3 && head == pat; -} - void ds_free_packs(demux_stream_t *ds) { demux_packet_t *dp = ds->first; @@ -783,11 +675,6 @@ void ds_free_packs(demux_stream_t *ds) free_demux_packet(dp); dp = dn; } - if (ds->asf_packet) { - // free unfinished .asf fragments: - free_demux_packet(ds->asf_packet); - ds->asf_packet = NULL; - } ds->first = ds->last = NULL; ds->packs = 0; // !!!!! ds->bytes = 0; @@ -1019,22 +906,6 @@ struct demuxer *demux_open_withparams(struct MPOpts *opts, if (demuxer_type) file_format = demuxer_type; - // Some code (e.g. dvd stuff, network code, or extension.c) explicitly - // request certain file formats. The list of formats are always handled by - // libavformat. - // Maybe attempts should be made to convert the mplayer format to the libav - // format, instead of reyling on libav to auto-detect the stream's format - // correctly. - switch (file_format) { - //case DEMUXER_TYPE_MPEG_PS: - //case DEMUXER_TYPE_MPEG_TS: - case DEMUXER_TYPE_Y4M: - case DEMUXER_TYPE_NSV: - case DEMUXER_TYPE_AAC: - case DEMUXER_TYPE_MPC: - file_format = DEMUXER_TYPE_LAVF; - } - // If somebody requested a demuxer check it if (file_format) { desc = get_demuxer_desc_from_type(file_format); @@ -1099,14 +970,7 @@ int demux_seek(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags) { if (!demuxer->seekable) { - if (demuxer->file_format == DEMUXER_TYPE_AVI) - mp_tmsg(MSGT_SEEK, MSGL_WARN, "Cannot seek in raw AVI streams. (Index required, try with the -idx switch.)\n"); -#ifdef CONFIG_TV - else if (demuxer->file_format == DEMUXER_TYPE_TV) - mp_tmsg(MSGT_SEEK, MSGL_WARN, "TV input is not seekable! (Seeking will probably be for changing channels ;)\n"); -#endif - else - mp_tmsg(MSGT_SEEK, MSGL_WARN, "Cannot seek in this file.\n"); + mp_tmsg(MSGT_SEEK, MSGL_WARN, "Cannot seek in this file.\n"); return 0; } diff --git a/demux/demux.h b/demux/demux.h index 20e6ba7a66..df73ddd4ee 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -32,42 +32,17 @@ struct MPOpts; -#if (__GNUC__ >= 3) -#define likely(x) __builtin_expect((x) != 0, 1) -#define unlikely(x) __builtin_expect((x) != 0, 0) -#else -#define likely(x) (x) -#define unlikely(x) (x) -#endif - #define MAX_PACKS 4096 #define MAX_PACK_BYTES 0x8000000 // 128 MiB enum demuxer_type { DEMUXER_TYPE_UNKNOWN = 0, - DEMUXER_TYPE_MPEG_PS, - DEMUXER_TYPE_AVI, - DEMUXER_TYPE_AVI_NI, - DEMUXER_TYPE_AVI_NINI, - DEMUXER_TYPE_ASF, DEMUXER_TYPE_TV, - DEMUXER_TYPE_Y4M, DEMUXER_TYPE_MF, DEMUXER_TYPE_RAWAUDIO, DEMUXER_TYPE_RAWVIDEO, - DEMUXER_TYPE_MPEG_ES, - DEMUXER_TYPE_MPEG4_ES, - DEMUXER_TYPE_H264_ES, - DEMUXER_TYPE_MPEG_PES, - DEMUXER_TYPE_MPEG_GXF, - DEMUXER_TYPE_GIF, - DEMUXER_TYPE_MPEG_TS, DEMUXER_TYPE_MATROSKA, DEMUXER_TYPE_LAVF, - DEMUXER_TYPE_NSV, - DEMUXER_TYPE_AVS, - DEMUXER_TYPE_AAC, - DEMUXER_TYPE_MPC, DEMUXER_TYPE_MNG, DEMUXER_TYPE_EDL, DEMUXER_TYPE_CUE, @@ -134,21 +109,10 @@ typedef struct demux_stream { demux_packet_t *current; // needed for refcounting of the buffer int id; // stream ID (for multiple audio/video streams) struct demuxer *demuxer; // parent demuxer structure (stream handler) -// ---- asf ----- - struct demux_packet *asf_packet; // read asf fragments here - int asf_seq; // ---- stream header ---- void *sh; // points to sh_audio or sh_video } demux_stream_t; -typedef struct demuxer_info { - char *name; - char *author; - char *encoder; - char *comments; - char *copyright; -} demuxer_info_t; - #define MAX_SH_STREAMS 256 #define MAX_A_STREAMS MAX_SH_STREAMS #define MAX_V_STREAMS MAX_SH_STREAMS @@ -300,15 +264,6 @@ struct demux_packet *demux_copy_packet(struct demux_packet *dp); #define SIZE_MAX ((size_t)-1) #endif -static inline void *realloc_struct(void *ptr, size_t nmemb, size_t size) -{ - if (nmemb > SIZE_MAX / size) { - free(ptr); - return NULL; - } - return realloc(ptr, nmemb * size); -} - void free_demuxer(struct demuxer *demuxer); int demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream, @@ -330,17 +285,6 @@ static inline int ds_tell_pts(struct demux_stream *ds) return (ds->pts_bytes - ds->buffer_size) + ds->buffer_pos; } -int demux_read_data(struct demux_stream *ds, unsigned char *mem, int len); -int demux_pattern_3(struct demux_stream *ds, unsigned char *mem, int maxlen, - int *read, uint32_t pattern); - -#define demux_peekc(ds) ( \ - (likely(ds->buffer_pos<ds->buffer_size)) ? ds->buffer[ds->buffer_pos] \ - : ((unlikely(!ds_fill_buffer(ds))) ? (-1) : ds->buffer[ds->buffer_pos])) -#define demux_getc(ds) ( \ - (likely(ds->buffer_pos<ds->buffer_size)) ? ds->buffer[ds->buffer_pos++] \ - : ((unlikely(!ds_fill_buffer(ds))) ? (-1) : ds->buffer[ds->buffer_pos++])) - void ds_free_packs(struct demux_stream *ds); int ds_get_packet(struct demux_stream *ds, unsigned char **start); int ds_get_packet_pts(struct demux_stream *ds, unsigned char **start, @@ -352,16 +296,6 @@ int ds_parse(struct demux_stream *sh, uint8_t **buffer, int *len, double pts, int64_t pos); void ds_clear_parser(struct demux_stream *sh); -static inline int avi_stream_id(unsigned int id) -{ - unsigned char a, b; - a = id - '0'; - b = (id >> 8) - '0'; - if (a>9 || b>9) - return 100; // invalid ID - return a * 10 + b; -} - struct demuxer *demux_open(struct MPOpts *opts, struct stream *stream, int file_format, int aid, int vid, int sid, char *filename); @@ -376,11 +310,6 @@ void demux_flush(struct demuxer *demuxer); int demux_seek(struct demuxer *demuxer, float rel_seek_secs, float audio_delay, int flags); -// AVI demuxer params: -extern int index_mode; // -1=untouched 0=don't use index 1=use (generate) index -extern int force_ni; -extern int pts_from_bps; - int demux_info_add(struct demuxer *demuxer, const char *opt, const char *param); int demux_info_add_bstr(struct demuxer *demuxer, struct bstr opt, struct bstr param); diff --git a/demux/demux_asf.c b/demux/demux_asf.c deleted file mode 100644 index f800e09dc3..0000000000 --- a/demux/demux_asf.c +++ /dev/null @@ -1,691 +0,0 @@ -/* - * ASF file parser for DEMUXER v0.3 - * copyright (c) 2001 A'rpi/ESP-team - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <limits.h> - -#include <libavutil/intreadwrite.h> - -#include "config.h" -#include "core/mp_msg.h" - -#include "stream/stream.h" -#include "asf.h" -#include "asfheader.h" -#include "demux.h" -#include "audio/decode/dec_audio.h" - -// based on asf file-format doc by Eugene [http://divx.euro.ru] - -/** - * \brief reads int stored in number of bytes given by len - * \param ptr pointer to read from, is incremented appropriately - * \param len lowest 2 bits indicate number of bytes to read - * \param def default value to return if len is invalid - */ -static inline unsigned read_varlen(uint8_t **ptr, int len, int def) { - const uint8_t *p = *ptr; - len &= 3; - switch (len) { - case 1: *ptr += 1; return *p; - case 2: *ptr += 2; return AV_RL16(p); - case 3: *ptr += 4; return AV_RL32(p); - } - return def; -} - -/** - * \brief checks if there is enough data to read the bytes given by len - * \param ptr pointer to read from - * \param endptr pointer to the end of the buffer - * \param len lowest 2 bits indicate number of bytes to read - */ -static inline int check_varlen(uint8_t *ptr, uint8_t *endptr, int len) { - return len&3 ? ptr + (1<<((len&3) - 1)) <= endptr : 1; -} - -static void asf_descrambling(unsigned char **src,unsigned len, struct asf_priv* asf){ - unsigned char *dst; - unsigned char *s2=*src; - unsigned i=0,x,y; - if (len > UINT_MAX - MP_INPUT_BUFFER_PADDING_SIZE) - return; - dst = malloc(len + MP_INPUT_BUFFER_PADDING_SIZE); - while(len>=asf->scrambling_h*asf->scrambling_w*asf->scrambling_b+i){ -// 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); - free(*src); - *src = dst; -} - -/***************************************************************** - * \brief initializes asf private data - * - */ -static void init_priv (struct asf_priv* asf){ - asf->last_vid_seq=-1; - asf->vid_ext_timing_index=-1; - asf->aud_ext_timing_index=-1; - asf->vid_ext_frame_index=-1; -} - -static void demux_asf_append_to_packet(demux_packet_t* dp,unsigned char *data,int len,int offs) -{ - 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); - size_t old_len = dp->len; - resize_demux_packet(dp, dp->len + len); - memcpy(dp->buffer + old_len, data, len); -} - -static int demux_asf_read_packet(demuxer_t *demux,unsigned char *data,int len,int id,int seq,uint64_t time,unsigned short dur,int offs,int keyframe){ - struct asf_priv* asf = demux->priv; - demux_stream_t *ds=NULL; - int close_seg=0; - - 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){ - demux_packet_t* dp=ds->asf_packet; - - if (ds==demux->video && asf->asf_is_dvr_ms) { - if (asf->new_vid_frame_seg) { - dp->pos=demux->filepos; - close_seg = 1; - } else seq = ds->asf_seq; - } else close_seg = ds->asf_seq!=seq; - - if(close_seg){ - // closed segment, finalize packet: - if(ds==demux->audio) - if(asf->scrambling_h>1 && asf->scrambling_w>1 && asf->scrambling_b>0) - asf_descrambling(&ds->asf_packet->buffer,ds->asf_packet->len,asf); - ds_add_packet(ds,ds->asf_packet); - ds->asf_packet=NULL; - } else { - // append data to it! - demux_asf_append_to_packet(dp,data,len,offs); - // 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); - if (asf->asf_is_dvr_ms) - dp->pts=time*0.0000001; - else - dp->pts=time*0.001; - dp->keyframe = 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; -} - -/***************************************************************** - * \brief read the replicated data associated with each segment - * \parameter pp reference to replicated data - * \parameter id stream number - * \parameter seq media object number - * \parameter keyframe key frame indicator - set to zero if keyframe, non-zero otherwise - * \parameter seg_time set to payload time when valid, if audio or new video frame payload, zero otherwise - * - */ -static void get_payload_extension_data(demuxer_t *demux, unsigned char** pp, unsigned char id, unsigned int seq, int *keyframe, uint64_t *seg_time){ - struct asf_priv* asf = demux->priv; - uint64_t payload_time = -1; //100ns units - int i, ext_max, ext_timing_index; - uint8_t *pi = *pp+4; - - 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->video->id && id!=demux->audio->id) return; - - if (id==demux->video->id) { - ext_max = asf->vid_repdata_count; - ext_timing_index = asf->vid_ext_timing_index; - } else { - ext_max = asf->aud_repdata_count; - ext_timing_index = asf->aud_ext_timing_index; - } - - *seg_time=0.0; - asf->new_vid_frame_seg = 0; - - for (i=0; i<ext_max; i++) { - uint16_t payextsize; - uint8_t segment_marker; - - if (id==demux->video->id) - payextsize = asf->vid_repdata_sizes[i]; - else - payextsize = asf->aud_repdata_sizes[i]; - - if (payextsize == 65535) { - payextsize = AV_RL16(pi); - pi+=2; - } - - // if this is the timing info extension then read the payload time - if (i == ext_timing_index) - payload_time = AV_RL64(pi+8); - - // if this is the video frame info extension then - // set the keyframe indicator, the 'new frame segment' indicator - // and (initially) the 'frame time' - if (i == asf->vid_ext_frame_index && id==demux->video->id) { - segment_marker = pi[0]; - // Known video stream segment_marker values that - // contain useful information: - // - // NTSC/ATSC (29.97fps): 0X4A 01001010 - // 0X4B 01001011 - // 0X49 01001001 - // - // PAL/ATSC (25fps): 0X3A 00111010 - // 0X3B 00111011 - // 0X39 00111001 - // - // ATSC progressive (29.97fps): 0X7A 01111010 - // 0X7B 01111011 - // 0X79 01111001 - // 11111111 - // ^ this is new video frame marker - // - // ^^^^ these bits indicate the framerate - // 0X4 is 29.97i, 0X3 is 25i, 0X7 is 29.97p, ???=25p - // - // ^^^ these bits indicate the frame type: - // 001 means I-frame - // 010 and 011 probably mean P and B - - asf->new_vid_frame_seg = (0X08 & segment_marker) && seq != asf->last_vid_seq; - - if (asf->new_vid_frame_seg) asf->last_vid_seq = seq; - - if (asf->avg_vid_frame_time == 0) { - // set the average frame time initially (in 100ns units). - // This is based on what works for known samples. - // It can be extended if more samples of different types can be obtained. - if (((segment_marker & 0XF0) >> 4) == 4) { - asf->avg_vid_frame_time = (uint64_t)((1.001 / 30.0) * 10000000.0); - asf->know_frame_time=1; - } else if (((segment_marker & 0XF0) >> 4) == 3) { - asf->avg_vid_frame_time = (uint64_t)(0.04 * 10000000.0); - asf->know_frame_time=1; - } else if (((segment_marker & 0XF0) >> 4) == 6) { - asf->avg_vid_frame_time = (uint64_t)(0.02 * 10000000.0); - asf->know_frame_time=1; - } else if (((segment_marker & 0XF0) >> 4) == 7) { - asf->avg_vid_frame_time = (uint64_t)((1.001 / 60.0) * 10000000.0); - asf->know_frame_time=1; - } else { - // we dont know the frame time initially so - // make a guess and then recalculate as we go. - asf->avg_vid_frame_time = (uint64_t)((1.001 / 60.0) * 10000000.0); - asf->know_frame_time=0; - } - } - *keyframe = (asf->new_vid_frame_seg && (segment_marker & 0X07) == 1); - } - pi +=payextsize; - } - - if (id==demux->video->id && asf->new_vid_frame_seg) { - asf->vid_frame_ct++; - // Some samples only have timings on key frames and - // the rest contain non-cronological timestamps. Interpolating - // the values between key frames works for all samples. - if (*keyframe) { - asf->found_first_key_frame=1; - if (!asf->know_frame_time && asf->last_key_payload_time > 0) { - // We dont know average frametime so recalculate. - // Giving precedence to the 'weight' of the existing - // average limits damage done to new value when there is - // a sudden time jump which happens occasionally. - asf->avg_vid_frame_time = - (0.9 * asf->avg_vid_frame_time) + - (0.1 * ((payload_time - asf->last_key_payload_time) / asf->vid_frame_ct)); - } - asf->last_key_payload_time = payload_time; - asf->vid_frame_ct = 1; - *seg_time = payload_time; - } else - *seg_time = (asf->last_key_payload_time + (asf->avg_vid_frame_time * (asf->vid_frame_ct-1))); - } - - if (id==demux->audio->id) { - if (payload_time != -1) - asf->last_aud_diff = payload_time - asf->last_aud_pts; - asf->last_aud_pts += asf->last_aud_diff; - *seg_time = asf->last_aud_pts; - } -} -//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 -static int demux_asf_fill_buffer(demuxer_t *demux, demux_stream_t *ds){ - struct asf_priv* asf = demux->priv; - - demux->filepos=stream_tell(demux->stream); - // Brodcast stream have movi_start==movi_end - // Better test ? - if((demux->movi_start < demux->movi_end) && (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->packetsize < 2) return 0; // Packet too short - - { - unsigned char* p=asf->packet; - unsigned char* p_end=asf->packet+asf->packetsize; - unsigned char flags=p[0]; - unsigned char segtype=p[1]; - unsigned padding; - unsigned plen; - unsigned sequence av_unused; - unsigned long time av_unused = 0; - unsigned short duration=0; - - int segs=1; - unsigned char segsizetype=0x80; - int seg=-1; - - if( mp_msg_test(MSGT_DEMUX,MSGL_DBG2) ){ - int i; - for(i=0;i<FFMIN(16, asf->packetsize);i++) printf(" %02X",asf->packet[i]); - printf("\n"); - } - - // skip ECC data if present by testing bit 7 of flags - // 1xxxbbbb -> ecc data present, skip bbbb byte(s) - // 0xxxxxxx -> payload parsing info starts - if (flags & 0x80) - { - p += (flags & 0x0f)+1; - if (p+1 >= p_end) return 0; // Packet too short - flags = p[0]; - segtype = p[1]; - } - - //if(segtype!=0x5d) printf("Warning! packet[4] != 0x5d \n"); - - p+=2; // skip flags & segtype - - // Read packet size (plen): - if(!check_varlen(p, p_end, flags>> 5)) return 0; // Not enough data - plen = read_varlen(&p, flags >> 5, 0); - - // Read sequence: - if(!check_varlen(p, p_end, flags>> 1)) return 0; // Not enough data - sequence = read_varlen(&p, flags >> 1, 0); - - // Read padding size (padding): - if(!check_varlen(p, p_end, flags>> 3)) return 0; // Not enough data - padding = read_varlen(&p, flags >> 3, 0); - - if(((flags>>5)&3)!=0){ - // Explicit (absoulte) packet size - 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); - } else { - // Padding (relative) size - plen=asf->packetsize-padding; - } - - // Read time & duration: - if (p+5 >= p_end) return 0; // Packet too short - time = AV_RL32(p); p+=4; - duration = AV_RL16(p); p+=2; - - // Read payload flags: - if(flags&1){ - // multiple sub-packets - if (p >= p_end) return 0; // Packet too short - segsizetype=p[0]>>6; - segs=p[0] & 0x3F; - ++p; - } - mp_dbg(MSGT_DEMUX,MSGL_DBG4,"%08"PRIu64": flag=%02X segs=%d seq=%u plen=%u pad=%u time=%ld dur=%d\n", - (uint64_t)demux->filepos,flags,segs,sequence,plen,padding,time,duration); - - for(seg=0;seg<segs;seg++){ - //ASF_segmhdr_t* sh; - unsigned char streamno; - unsigned int seq; - unsigned int x; // offset or timestamp - unsigned int rlen; - // - int len; - uint64_t time2=0; - int keyframe=0; - - if(p>=p_end) { - mp_msg(MSGT_DEMUX,MSGL_V,"Warning! invalid packet 1, aborting parsing...\n"); - break; - } - - if( mp_msg_test(MSGT_DEMUX,MSGL_DBG2) ){ - int i; - printf("seg %d:",seg); - for(i=0;i<FFMIN(16, p_end - p);i++) printf(" %02X",p[i]); - printf("\n"); - } - - streamno=p[0]&0x7F; - if(p[0]&0x80) keyframe=1; - p++; - - // Read media object number (seq): - if(!check_varlen(p, p_end, segtype >> 4)) break; // Not enough data - seq = read_varlen(&p, segtype >> 4, 0); - - // Read offset or timestamp: - if(!check_varlen(p, p_end, segtype >> 2)) break; // Not enough data - x = read_varlen(&p, segtype >> 2, 0); - - // Read replic.data len: - if(!check_varlen(p, p_end, segtype)) break; // Not enough data - rlen = read_varlen(&p, segtype, 0); - -// printf("### rlen=%d \n",rlen); - if (rlen > p_end - p) { - mp_msg(MSGT_DEMUX, MSGL_V, "invalid rlen=%u\n", rlen); - break; - } - - switch(rlen){ - case 0x01: // 1 = special, means grouping - //printf("grouping: %02X \n",p[0]); - ++p; // skip PTS delta - break; - default: - if(rlen>=8){ - p+=4; // skip object size - if (p+3 >= p_end) break; // Packet too short - time2=AV_RL32(p); // read PTS - if (asf->asf_is_dvr_ms) - get_payload_extension_data(demux, &p, streamno, seq, &keyframe, &time2); - p+=rlen-4; - } else { - mp_msg(MSGT_DEMUX,MSGL_V,"unknown segment type (rlen): 0x%02X \n",rlen); - time2=0; // unknown - p+=rlen; - } - } - - if(flags&1){ - // multiple segments - if(!check_varlen(p, p_end, segsizetype)) break; // Not enough data - len = read_varlen(&p, segsizetype, plen-(p-asf->packet)); - } 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); - len = p_end - p; - } - mp_dbg(MSGT_DEMUX,MSGL_DBG4," seg #%d: streamno=%d seq=%d type=%02X len=%d\n",seg,streamno,seq,rlen,len); - - switch(rlen){ - 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); - if(len2 > len - 1 || len2 < 0) break; // Not enough data - len2 = FFMIN(len2, asf->packetsize); - demux_asf_read_packet(demux,p,len2,streamno,seq,x,duration,-1,keyframe); - p+=len2; - len-=len2+1; - ++seq; - } - if(len!=0){ - mp_msg(MSGT_DEMUX,MSGL_V,"ASF_parser: warning! groups total != len\n"); - } - break; - default: - // NO GROUPING: - //printf("fragment offset: %d \n",sh->x); - if (len <= 0) break; - if (!asf->asf_is_dvr_ms || asf->found_first_key_frame) { - len = FFMIN(len, asf->packetsize); - 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,"%08"PRIX64": UNKNOWN TYPE %02X %02X %02X %02X %02X...\n",(int64_t)demux->filepos,asf->packet[0],asf->packet[1],asf->packet[2],asf->packet[3],asf->packet[4]); - return 0; -} - -#include "stheader.h" - -static void demux_seek_asf(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags){ - struct asf_priv* asf = 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; - - //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=asf->packetrate; // packets / sec - int64_t rel_seek_packs=(flags&SEEK_FACTOR)? // FIXME: int may be enough? - (rel_seek_secs*(demuxer->movi_end-demuxer->movi_start)/asf->packetsize): - (rel_seek_secs*p_rate); - int64_t rel_seek_bytes=rel_seek_packs*asf->packetsize; - int64_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&SEEK_ABSOLUTE)?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); - - if (asf->asf_is_dvr_ms) asf->dvr_last_vid_pts = 0.0f; - - if (d_video->id >= 0) - ds_fill_buffer(d_video); - if(sh_audio){ - ds_fill_buffer(d_audio); - } - - if (d_video->id >= 0) - 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->keyframe) - break; - if(!ds_fill_buffer(d_video)) break; // skip frame. EOF? - } - - -} - -static int demux_asf_control(demuxer_t *demuxer,int cmd, void *arg){ - struct asf_priv* asf = 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; -*/ - switch(cmd) { - case DEMUXER_CTRL_GET_TIME_LENGTH: - *((double *)arg)=asf->movielength; - return DEMUXER_CTRL_OK; - - default: - return DEMUXER_CTRL_NOTIMPL; - } -} - - -static demuxer_t* demux_open_asf(demuxer_t* demuxer) -{ - struct asf_priv* asf = demuxer->priv; - sh_video_t *sh_video=NULL; - - //---- ASF header: - if(!asf) return NULL; - init_priv(asf); - if (!read_asf_header(demuxer,asf)) - return NULL; - stream_seek(demuxer->stream,demuxer->movi_start); -// demuxer->idx_pos=0; -// demuxer->endpos=avi_header.movi_end; - if(demuxer->video->id != -2) { - if(!ds_fill_buffer(demuxer->video)){ - mp_msg(MSGT_DEMUXER, MSGL_WARN, "ASF: %s", - mp_gtext("No video stream found.\n")); - demuxer->video->sh=NULL; - //printf("ASF: missing video stream!? contact the author, it may be a bug :(\n"); - } else { - sh_video=demuxer->video->sh; - sh_video->fps=1000.0f; sh_video->frametime=0.001f; - - if (asf->asf_is_dvr_ms) { - sh_video->bih->biWidth = 0; - sh_video->bih->biHeight = 0; - } - } - } - - if(demuxer->audio->id!=-2){ - mp_tmsg(MSGT_DEMUXER,MSGL_V,"ASF: Searching for audio stream (id:%d).\n",demuxer->audio->id); - if(!ds_fill_buffer(demuxer->audio)){ - mp_msg(MSGT_DEMUXER, MSGL_INFO, "ASF: %s", - mp_gtext("No audio stream found -> no sound.\n")); - demuxer->audio->sh=NULL; - } - } - if(!demuxer->stream->seek) - demuxer->seekable=0; - - return demuxer; -} - - -static void demux_close_asf(demuxer_t *demuxer) { - struct asf_priv* asf = demuxer->priv; - - if (!asf) return; - - free(asf->aud_repdata_sizes); - free(asf->vid_repdata_sizes); - free(asf->packet); - free(asf); -} - -const demuxer_desc_t demuxer_desc_asf = { - "ASF demuxer", - "asf", - "ASF", - "A'rpi", - "ASF, WMV, WMA", - DEMUXER_TYPE_ASF, - 1, // safe autodetect - asf_check_header, - demux_asf_fill_buffer, - demux_open_asf, - demux_close_asf, - demux_seek_asf, - demux_asf_control -}; diff --git a/demux/demux_avi.c b/demux/demux_avi.c deleted file mode 100644 index a07f022cde..0000000000 --- a/demux/demux_avi.c +++ /dev/null @@ -1,899 +0,0 @@ -/* - * AVI file parser for DEMUXER v2.9 - * Copyright (c) 2001 A'rpi/ESP-team - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include "config.h" -#include "core/mp_msg.h" - -#include "stream/stream.h" -#include "demux.h" -#include "stheader.h" -#include "aviheader.h" - -extern const demuxer_desc_t demuxer_desc_avi_ni; -extern const demuxer_desc_t demuxer_desc_avi_nini; - -// PTS: 0=interleaved 1=BPS-based -int pts_from_bps=1; - -static void update_audio_block_size(demuxer_t *demux) -{ - avi_priv_t *priv = demux->priv; - sh_audio_t *sh = demux->audio->sh; - if (!sh) - return; - priv->audio_block_size = sh->audio.dwSampleSize; - if (sh->wf) { - priv->audio_block_size = sh->wf->nBlockAlign; - if (!priv->audio_block_size) { - // for PCM audio we can calculate the blocksize: - if (sh->format == 1) - priv->audio_block_size = sh->wf->nChannels*(sh->wf->wBitsPerSample/8); - else - priv->audio_block_size = 1; // hope the best... - } else { - // workaround old mencoder bug: - if (sh->audio.dwSampleSize == 1 && sh->audio.dwScale == 1 && - (sh->wf->nBlockAlign == 1152 || sh->wf->nBlockAlign == 576)) { - mp_tmsg(MSGT_DEMUX,MSGL_WARN,"AVI: Working around CBR-MP3 nBlockAlign header bug!\n"); - priv->audio_block_size = 1; - } - } - } -} - -// Select ds from ID -static demux_stream_t *demux_avi_select_stream(demuxer_t *demux, - unsigned int id) -{ - int stream_id=avi_stream_id(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); - update_audio_block_size(demux); - } - 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); - //abort(); - } - return NULL; -} - -static int valid_fourcc(unsigned int id){ - static const char valid[] = "0123456789abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"; - unsigned char* fcc=(unsigned char*)(&id); - return strchr(valid, fcc[0]) && strchr(valid, fcc[1]) && - strchr(valid, fcc[2]) && strchr(valid, fcc[3]); -} - -static int valid_stream_id(unsigned int id) { - unsigned char* fcc=(unsigned char*)(&id); - return fcc[0] >= '0' && fcc[0] <= '9' && fcc[1] >= '0' && fcc[1] <= '9' && - ((fcc[2] == 'w' && fcc[3] == 'b') || (fcc[2] == 'd' && fcc[3] == 'c')); -} - -static int choose_chunk_len(unsigned int len1,unsigned int len2){ - // len1 has a bit more priority than len2. len1!=len2 - // Note: this is a first-idea-logic, may be wrong. comments welcomed. - - // prefer small frames rather than 0 - if(!len1) return (len2>0x80000) ? len1 : len2; - if(!len2) return (len1>0x100000) ? len2 : len1; - - // choose the smaller value: - return (len1<len2)? len1 : len2; -} - -static int demux_avi_read_packet(demuxer_t *demux,demux_stream_t *ds,unsigned int id,unsigned int len,int idxpos,int flags){ - avi_priv_t *priv=demux->priv; - int skip; - float pts=0; - - mp_dbg(MSGT_DEMUX,MSGL_DBG3,"demux_avi.read_packet: %X\n",id); - - if(ds==demux->audio){ - if(priv->pts_corrected==0){ - if(priv->pts_has_video){ - // we have video pts now - float delay=0; - if(((sh_audio_t*)(ds->sh))->wf->nAvgBytesPerSec) - 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; - } - if(pts_from_bps){ - pts = priv->audio_block_no * - (float)((sh_audio_t*)demux->audio->sh)->audio.dwScale / - (float)((sh_audio_t*)demux->audio->sh)->audio.dwRate; - } else - pts=priv->avi_audio_pts; //+priv->pts_correction; - priv->avi_audio_pts=0; - // update blockcount: - priv->audio_block_no+= - (len+priv->audio_block_size-1)/priv->audio_block_size; - } else - if(ds==demux->video){ - // video - if(priv->skip_video_frames>0){ - // drop frame (seeking) - --priv->skip_video_frames; - ds=NULL; - } - - pts = priv->avi_video_pts = priv->video_pack_no * - (float)((sh_video_t*)demux->video->sh)->video.dwScale / - (float)((sh_video_t*)demux->video->sh)->video.dwRate; - - priv->avi_audio_pts=priv->avi_video_pts+priv->pts_correction; - priv->pts_has_video=1; - - if(ds) ++priv->video_pack_no; - - } - - 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; - } - skip = FFMAX(skip, 0); - if (avi_stream_id(id) > 99 && id != mmioFOURCC('J','U','N','K')) - skip = FFMIN(skip, 65536); - 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; -} - -static uint32_t avi_find_id(stream_t *stream) { - uint32_t id = stream_read_dword_le(stream); - if (!id) { - mp_msg(MSGT_DEMUX, MSGL_WARN, "Incomplete stream? Trying resync.\n"); - do { - id = stream_read_dword_le(stream); - if (stream_eof(stream)) return 0; - } while (avi_stream_id(id) > 99); - } - return id; -} - -// return value: -// 0 = EOF or no stream found -// 1 = successfully read a packet -static int demux_avi_fill_buffer(demuxer_t *demux, demux_stream_t *dsds){ -avi_priv_t *priv=demux->priv; -unsigned int id=0; -unsigned int len; -int ret=0; -demux_stream_t *ds; - -do{ - int flags=1; - AVIINDEXENTRY *idx=NULL; - if(priv->idx_size>0 && priv->idx_pos<priv->idx_size){ - int64_t pos; - - idx=&((AVIINDEXENTRY *)priv->idx)[priv->idx_pos++]; - - if(idx->dwFlags&AVIIF_LIST){ - if (!valid_stream_id(idx->ckid)) - // LIST - continue; - if (!priv->warned_unaligned) - mp_msg(MSGT_DEMUX, MSGL_WARN, "Looks like unaligned chunk in index, broken AVI file!\n"); - priv->warned_unaligned = 1; - } - 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 = (int64_t)priv->idx_offset+AVI_IDX_OFFSET(idx); - if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start) && (demux->stream->flags & MP_STREAM_SEEK)){ - mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! idx=0x%"PRIX64" \n",(int64_t)pos); - continue; - } - 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); - if(valid_fourcc(idx->ckid)) - id=idx->ckid; // use index if valid - else - if(!valid_fourcc(id)) continue; // drop chunk if both id and idx bad - } - len=stream_read_dword_le(demux->stream); - if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){ - mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%d \n",len,idx->dwChunkLength); - if(len>0x200000 && idx->dwChunkLength>0x200000) continue; // both values bad :( - len=choose_chunk_len(idx->dwChunkLength,len); - } - if(!(idx->dwFlags&AVIIF_KEYFRAME)) flags=0; - } else { - demux->filepos=stream_tell(demux->stream); - if(demux->filepos>=demux->movi_end && demux->movi_end>demux->movi_start && (demux->stream->flags & MP_STREAM_SEEK)){ - demux->stream->eof=1; - return 0; - } - id=avi_find_id(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==mmioFOURCC('R', 'I', 'F', 'F')){ - id=stream_read_dword_le(demux->stream); // list or RIFF type - continue; - } - } - - ds=demux_avi_select_stream(demux,id); - if(ds) - if(ds->packs+1>=MAX_PACKS || ds->bytes+len>=MAX_PACK_BYTES){ - // this packet will cause a buffer overflow, switch to -ni mode!!! - mp_tmsg(MSGT_DEMUX,MSGL_WARN,"\nBadly interleaved AVI file detected - switching to --avi-ni mode...\n"); - if(priv->idx_size>0){ - // has index - demux->type=DEMUXER_TYPE_AVI_NI; - demux->desc=&demuxer_desc_avi_ni; - --priv->idx_pos; // hack - } else { - // no index - demux->type=DEMUXER_TYPE_AVI_NINI; - demux->desc=&demuxer_desc_avi_nini; - priv->idx_pos=demux->filepos; // hack - } - priv->idx_pos_v=priv->idx_pos_a=priv->idx_pos; - // quit now, we can't even (no enough buffer memory) read this packet :( - return -1; - } - - ret=demux_avi_read_packet(demux,ds,id,len,priv->idx_pos-1,flags); -} while(ret!=1); - return 1; -} - - -// return value: -// 0 = EOF or no stream found -// 1 = successfully read a packet -static 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 ret=0; - -do{ - int flags=1; - 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){ - int64_t pos; - idx=&((AVIINDEXENTRY *)priv->idx)[idx_pos]; - - if(idx->dwFlags&AVIIF_LIST){ - if (!valid_stream_id(idx->ckid)) - // LIST - continue; - if (!priv->warned_unaligned) - mp_msg(MSGT_DEMUX, MSGL_WARN, "Looks like unaligned chunk in index, broken AVI file!\n"); - priv->warned_unaligned = 1; - } - 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 = priv->idx_offset+AVI_IDX_OFFSET(idx); - if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start)){ - mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! current=0x%"PRIX64" idx=0x%"PRIX64" \n",(int64_t)demux->filepos,(int64_t)pos); - continue; - } - 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); - if(valid_fourcc(idx->ckid)) - id=idx->ckid; // use index if valid - else - if(!valid_fourcc(id)) continue; // drop chunk if both id and idx bad - } - len=stream_read_dword_le(demux->stream); - if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){ - mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%d \n",len,idx->dwChunkLength); - if(len>0x200000 && idx->dwChunkLength>0x200000) continue; // both values bad :( - len=choose_chunk_len(idx->dwChunkLength,len); - } - if(!(idx->dwFlags&AVIIF_KEYFRAME)) flags=0; - } else return 0; - ret=demux_avi_read_packet(demux,demux_avi_select_stream(demux,id),id,len,idx_pos,flags); -} while(ret!=1); - return 1; -} - - -// return value: -// 0 = EOF or no stream found -// 1 = successfully read a packet -static 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; -int64_t *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->movi_end>demux->movi_start)){ - ds->eof=1; - return 0; - } - - id=avi_find_id(demux->stream); - len=stream_read_dword_le(demux->stream); - - if(stream_eof(demux->stream)) return 0; - - if(id==mmioFOURCC('L','I','S','T')){ - id=stream_read_dword_le(demux->stream); // list type - continue; - } - - if(id==mmioFOURCC('R','I','F','F')){ - mp_msg(MSGT_DEMUX,MSGL_V,"additional RIFF header...\n"); - id=stream_read_dword_le(demux->stream); // "AVIX" - continue; - } - - if(ds==demux_avi_select_stream(demux,id)){ - // read it! - ret=demux_avi_read_packet(demux,ds,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; -} - -// AVI demuxer parameters: -int index_mode=-1; // -1=untouched 0=don't use index 1=use (generate) index -int force_ni=0; // force non-interleaved AVI parsing - -static 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=calloc(1, sizeof(avi_priv_t)); - - demuxer->priv=(void*)priv; - - //---- AVI header: - read_avi_header(demuxer,(demuxer->stream->flags & MP_STREAM_SEEK_BW)?index_mode:-2); - update_audio_block_size(demuxer); - - if(demuxer->audio->id>=0 && !demuxer->a_streams[demuxer->audio->id]){ - mp_tmsg(MSGT_DEMUX,MSGL_WARN,"AVI: invalid audio stream ID: %d - ignoring (nosound)\n",demuxer->audio->id); - demuxer->audio->id=-2; // disabled - } - if(demuxer->video->id>=0 && !demuxer->v_streams[demuxer->video->id]){ - mp_tmsg(MSGT_DEMUX,MSGL_WARN,"AVI: invalid video stream ID: %d - ignoring (using default)\n",demuxer->video->id); - demuxer->video->id=-1; // autodetect - } - - stream_seek(demuxer->stream,demuxer->movi_start); - if(priv->idx_size>1){ - // decide index format: -#if 1 - if((AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[0])<demuxer->movi_start || - AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[1])<demuxer->movi_start )&& !priv->isodml) - priv->idx_offset=demuxer->movi_start-4; -#else - if(AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[0])<demuxer->movi_start) - priv->idx_offset=demuxer->movi_start-4; -#endif - mp_msg(MSGT_DEMUX,MSGL_V,"AVI index offset: 0x%X (movi=0x%X idx0=0x%X idx1=0x%X)\n", - (int)priv->idx_offset,(int)demuxer->movi_start, - (int)((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset, - (int)((AVIINDEXENTRY *)priv->idx)[1].dwChunkOffset); - } - - if(priv->idx_size>0){ - // check that file is non-interleaved: - int i; - int64_t a_pos=-1; - int64_t 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); - int64_t pos = priv->idx_offset + AVI_IDX_OFFSET(idx); - 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: %s", - mp_gtext("No video stream found.\n")); - return NULL; - } - if(a_pos==-1){ - d_audio->sh=sh_audio=NULL; - } else { - if(force_ni || abs(a_pos-v_pos)>0x100000){ // distance > 1MB - mp_tmsg(MSGT_DEMUX,MSGL_INFO,"%s NON-INTERLEAVED AVI file format.\n",force_ni?"Forced":"Detected"); - demuxer->type=DEMUXER_TYPE_AVI_NI; // HACK!!!! - demuxer->desc=&demuxer_desc_avi_ni; // HACK!!!! - pts_from_bps=1; // force BPS sync! - } - } - } else { - // no index - if(force_ni){ - mp_tmsg(MSGT_DEMUX,MSGL_INFO,"Using NON-INTERLEAVED broken AVI file format.\n"); - demuxer->type=DEMUXER_TYPE_AVI_NINI; // HACK!!!! - demuxer->desc=&demuxer_desc_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: %s", - mp_gtext("Missing video stream!? Contact the author, " - "it may be a bug :(\n")); - return NULL; - } - 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(!priv->audio_streams || !ds_fill_buffer(d_audio)){ - mp_msg(MSGT_DEMUX, MSGL_INFO, "AVI: %s", - mp_gtext("No audio stream found -> no sound.\n")); - d_audio->sh=sh_audio=NULL; - } else { - sh_audio=d_audio->sh;sh_audio->ds=d_audio; - } - } - - // calculating audio/video bitrate: - if(priv->idx_size>0){ - // we have index, let's count 'em! - AVIINDEXENTRY *idx = priv->idx; - int64_t vsize=0; - int64_t asize=0; - size_t vsamples=0; - size_t asamples=0; - int i; - for(i=0;i<priv->idx_size;i++){ - int id=avi_stream_id(idx[i].ckid); - unsigned len=idx[i].dwChunkLength; - if(sh_video->ds->id == id) { - vsize+=len; - ++vsamples; - } - else if(sh_audio && sh_audio->ds->id == id) { - asize+=len; - asamples+=(len+priv->audio_block_size-1)/priv->audio_block_size; - } - } - mp_msg(MSGT_DEMUX, MSGL_V, - "AVI video size=%"PRId64" (%zu) audio size=%"PRId64" (%zu)\n", - vsize, vsamples, asize, asamples); - priv->numberofframes=vsamples; - sh_video->i_bps=((float)vsize/(float)vsamples)*(float)sh_video->video.dwRate/(float)sh_video->video.dwScale; - if(sh_audio) sh_audio->i_bps=((float)asize/(float)asamples)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale; - } else { - // guessing, results may be inaccurate: - int64_t vsize; - int64_t asize=0; - - if((priv->numberofframes=sh_video->video.dwLength)<=1) - // bad video header, try to get number of frames from audio - if(sh_audio && sh_audio->wf->nAvgBytesPerSec) priv->numberofframes=sh_video->fps*sh_audio->audio.dwLength/sh_audio->audio.dwRate*sh_audio->audio.dwScale; - if(priv->numberofframes<=1){ - mp_tmsg(MSGT_SEEK,MSGL_WARN,"Could not determine number of frames (for absolute seek).\n"); - priv->numberofframes=0; - } - - if(sh_audio){ - if(sh_audio->wf->nAvgBytesPerSec && sh_audio->audio.dwSampleSize!=1){ - asize=(float)sh_audio->wf->nAvgBytesPerSec*sh_audio->audio.dwLength*sh_audio->audio.dwScale/sh_audio->audio.dwRate; - } else { - asize=sh_audio->audio.dwLength; - sh_audio->i_bps=(float)asize/(sh_video->frametime*priv->numberofframes); - } - } - vsize=demuxer->movi_end-demuxer->movi_start-asize-8*priv->numberofframes; - mp_msg(MSGT_DEMUX,MSGL_V,"AVI video size=%"PRId64" (%u) audio size=%"PRId64"\n",vsize,priv->numberofframes,asize); - sh_video->i_bps=(float)vsize/(sh_video->frametime*priv->numberofframes); - } - - return demuxer; - -} - - -static void demux_seek_avi(demuxer_t *demuxer, float rel_seek_secs, - float audio_delay, 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&SEEK_ABSOLUTE){ - // seek absolute - video_chunk_pos=0; - } - - if(flags&SEEK_FACTOR){ - rel_seek_frames=rel_seek_secs*priv->numberofframes; - } - - 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-1){ - 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; - } - priv->video_pack_no=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; - priv->audio_block_no=0; - d_audio->dpos=0; - - if(sh_audio){ - int i; - 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 - /* immediate seeking to audio position, including when streams are delayed */ - curr_audio_pos=(priv->avi_video_pts + audio_delay)*(float)sh_audio->audio.dwRate/(float)sh_audio->audio.dwScale; - curr_audio_pos*=sh_audio->audio.dwSampleSize; - - // 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; - if(d_audio->dpos<=curr_audio_pos && curr_audio_pos<(d_audio->dpos+len)){ - break; - } - ++d_audio->pack_no; - priv->audio_block_no+= - (len+priv->audio_block_size-1)/priv->audio_block_size; - d_audio->dpos+=len; - } - } - audio_chunk_pos=i; - skip_audio_bytes=curr_audio_pos-d_audio->dpos; - - mp_msg(MSGT_SEEK,MSGL_V,"SEEK: i=%d (max:%d) dpos=%d (wanted:%d) \n", - i,chunk_max,(int)d_audio->dpos,curr_audio_pos); - - } else { - // VBR audio - /* immediate seeking to audio position, including when streams are delayed */ - int chunks=(priv->avi_video_pts + audio_delay)*(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; - priv->audio_block_no+= - (len+priv->audio_block_size-1)/priv->audio_block_size; - d_audio->dpos+=len; - audio_chunk_pos=i; - } - chunks-=(len+priv->audio_block_size-1)/priv->audio_block_size; - } - } - } - - // 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; - - 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->avi_audio_pts=priv->avi_video_pts; - // set index position: - 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", - (int)priv->idx_pos,audio_chunk_pos,video_chunk_pos, - (int)priv->skip_video_frames,skip_audio_bytes,skip_audio_secs); - - if(skip_audio_bytes){ - demux_read_data(d_audio,NULL,skip_audio_bytes); - } - - } - d_video->pts=priv->avi_video_pts; // OSD - -} - - -static void demux_close_avi(demuxer_t *demuxer) -{ - avi_priv_t* priv=demuxer->priv; - - if(!priv) - return; - - if(priv->idx_size > 0) - free(priv->idx); - free(priv); -} - - -static int demux_avi_control(demuxer_t *demuxer,int cmd, void *arg){ - avi_priv_t *priv=demuxer->priv; - demux_stream_t *d_video=demuxer->video; - sh_video_t *sh_video=d_video->sh; - - switch(cmd) { - case DEMUXER_CTRL_GET_TIME_LENGTH: - if (!priv->numberofframes || !sh_video) return DEMUXER_CTRL_DONTKNOW; - *((double *)arg)=(double)priv->numberofframes/sh_video->fps; - if (sh_video->video.dwLength<=1) return DEMUXER_CTRL_GUESS; - return DEMUXER_CTRL_OK; - - case DEMUXER_CTRL_SWITCH_AUDIO: - case DEMUXER_CTRL_SWITCH_VIDEO: { - int audio = (cmd == DEMUXER_CTRL_SWITCH_AUDIO); - demux_stream_t *ds = audio ? demuxer->audio : demuxer->video; - void **streams = audio ? (void **)demuxer->a_streams : (void **)demuxer->v_streams; - int maxid = FFMIN(100, audio ? MAX_A_STREAMS : MAX_V_STREAMS); - int chunkid; - if (ds->id < -1) - ds->id = -1; - - if (*(int *)arg >= 0) - ds->id = *(int *)arg; - else { - int i; - for (i = 0; i < maxid; i++) { - if (++ds->id >= maxid) ds->id = 0; - if (streams[ds->id]) break; - } - } - - chunkid = (ds->id / 10 + '0') | (ds->id % 10 + '0') << 8; - ds->sh = NULL; - if (!streams[ds->id]) // stream not available - ds->id = -1; - else - demux_avi_select_stream(demuxer, chunkid); - *(int *)arg = ds->id; - return DEMUXER_CTRL_OK; - } - - default: - return DEMUXER_CTRL_NOTIMPL; - } -} - - -static int avi_check_file(demuxer_t *demuxer) -{ - int id=stream_read_dword_le(demuxer->stream); // "RIFF" - - if((id==mmioFOURCC('R','I','F','F')) || (id==mmioFOURCC('O','N','2',' '))) { - stream_read_dword_le(demuxer->stream); //filesize - id=stream_read_dword_le(demuxer->stream); // "AVI " - if(id==formtypeAVI) - return DEMUXER_TYPE_AVI; - // "Samsung Digimax i6 PMP" crap according to bug 742 - if(id==mmioFOURCC('A','V','I',0x19)) - return DEMUXER_TYPE_AVI; - if(id==mmioFOURCC('O','N','2','f')){ - mp_tmsg(MSGT_DEMUXER,MSGL_INFO,"ON2 AVI format"); - return DEMUXER_TYPE_AVI; - } - } - - return 0; -} - - -const demuxer_desc_t demuxer_desc_avi = { - "AVI demuxer", - "avi", - "AVI", - "Arpi?", - "AVI files, including non interleaved files", - DEMUXER_TYPE_AVI, - 1, // safe autodetect - avi_check_file, - demux_avi_fill_buffer, - demux_open_avi, - demux_close_avi, - demux_seek_avi, - demux_avi_control -}; - -const demuxer_desc_t demuxer_desc_avi_ni = { - "AVI demuxer, non-interleaved", - "avini", - "AVI", - "Arpi?", - "AVI files, including non interleaved files", - DEMUXER_TYPE_AVI, - 1, // safe autodetect - avi_check_file, - demux_avi_fill_buffer_ni, - demux_open_avi, - demux_close_avi, - demux_seek_avi, - demux_avi_control -}; - -const demuxer_desc_t demuxer_desc_avi_nini = { - "AVI demuxer, non-interleaved and no index", - "avinini", - "AVI", - "Arpi?", - "AVI files, including non interleaved files", - DEMUXER_TYPE_AVI, - 1, // safe autodetect - avi_check_file, - demux_avi_fill_buffer_nini, - demux_open_avi, - demux_close_avi, - demux_seek_avi, - demux_avi_control -}; diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 39e1cb28c5..466ab7537b 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -510,7 +510,7 @@ static demuxer_t *demux_open_lavf(demuxer_t *demuxer) if (opts->user_correct_pts != 0) avfc->flags |= AVFMT_FLAG_GENPTS; } - if (index_mode == 0) + if (opts->index_mode == 0) avfc->flags |= AVFMT_FLAG_IGNIDX; if (lavfdopts->probesize) { diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 1c93fa588c..724bf6255b 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -722,10 +722,11 @@ static void add_block_position(demuxer_t *demuxer, struct mkv_track *track, static int demux_mkv_read_cues(demuxer_t *demuxer) { + struct MPOpts *opts = demuxer->opts; mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; stream_t *s = demuxer->stream; - if (index_mode == 0 || index_mode == 2) { + if (opts->index_mode == 0 || opts->index_mode == 2) { ebml_read_skip(s, NULL); return 0; } diff --git a/demux/demux_mpg.c b/demux/demux_mpg.c deleted file mode 100644 index d47b3afd86..0000000000 --- a/demux/demux_mpg.c +++ /dev/null @@ -1,1306 +0,0 @@ -/* - * MPG/VOB file parser for DEMUXER v2.5 - * copyright (c) 2001 by A'rpi/ESP-team - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <math.h> - -#include "config.h" -#include "core/mp_msg.h" -#include "core/options.h" - -#include "libavutil/attributes.h" -#include "audio/decode/dec_audio.h" -#include "stream/stream.h" -#include "demux.h" -#include "parse_es.h" -#include "stheader.h" -#include "mp3_hdr.h" - -//#define MAX_PS_PACKETSIZE 2048 -#define MAX_PS_PACKETSIZE (224*1024) - -#define UNKNOWN 0 -#define VIDEO_MPEG1 0x10000001 -#define VIDEO_MPEG2 0x10000002 -#define VIDEO_MPEG4 0x10000004 -#define VIDEO_H264 0x10000005 -#define AUDIO_MP2 0x50 -#define AUDIO_A52 0x2000 -#define AUDIO_LPCM_BE 0x10001 -#define AUDIO_AAC mmioFOURCC('M', 'P', '4', 'A') - -typedef struct mpg_demuxer { - float last_pts; - float first_pts; // first pts found in stream - float first_to_final_pts_len; // difference between final pts and first pts - int has_valid_timestamps; // !=0 iff time stamps look linear - // (not necessarily starting with 0) - unsigned int es_map[0x40]; //es map of stream types (associated to the pes id) from 0xb0 to 0xef - int num_a_streams; - int a_stream_ids[MAX_A_STREAMS]; -} mpg_demuxer_t; - -static int mpeg_pts_error=0; -int64_t ps_probe = 0; - -static int parse_psm(demuxer_t *demux, int len) { - unsigned char c, id, type; - unsigned int plen, prog_len, es_map_len; - mpg_demuxer_t *priv = (mpg_demuxer_t *) demux->priv; - - mp_dbg(MSGT_DEMUX,MSGL_V, "PARSE_PSM, len=%d\n", len); - if(! len || len > 1018) - return 0; - - c = stream_read_char(demux->stream); - if(! (c & 0x80)) { - stream_skip(demux->stream, len - 1); //not yet valid, discard - return 0; - } - stream_skip(demux->stream, 1); - prog_len = stream_read_word(demux->stream); //length of program descriptors - stream_skip(demux->stream, prog_len); //.. that we ignore - es_map_len = stream_read_word(demux->stream); //length of elementary streams map - es_map_len = FFMIN(es_map_len, len - prog_len - 8); //sanity check - while(es_map_len > 0) { - type = stream_read_char(demux->stream); - id = stream_read_char(demux->stream); - if(id >= 0xB0 && id <= 0xEF && priv) { - int idoffset = id - 0xB0; - switch(type) { - case 0x1: - priv->es_map[idoffset] = VIDEO_MPEG1; - break; - case 0x2: - priv->es_map[idoffset] = VIDEO_MPEG2; - break; - case 0x3: - case 0x4: - priv->es_map[idoffset] = AUDIO_MP2; - break; - case 0x0f: - case 0x11: - priv->es_map[idoffset] = AUDIO_AAC; - break; - case 0x10: - priv->es_map[idoffset] = VIDEO_MPEG4; - break; - case 0x1b: - priv->es_map[idoffset] = VIDEO_H264; - break; - case 0x81: - priv->es_map[idoffset] = AUDIO_A52; - break; - } - mp_dbg(MSGT_DEMUX,MSGL_V, "PSM ES, id=0x%x, type=%x, stype: %x\n", id, type, priv->es_map[idoffset]); - } - plen = stream_read_word(demux->stream); //length of elementary stream descriptors - plen = FFMIN(plen, es_map_len); //sanity check - stream_skip(demux->stream, plen); //skip descriptors for now - es_map_len -= 4 + plen; - } - stream_skip(demux->stream, 4); //skip crc32 - return 1; -} - -// 500000 is a wild guess -#define TIMESTAMP_PROBE_LEN 500000 - -//MAX_PTS_DIFF_FOR_CONSECUTIVE denotes the maximum difference -//between two pts to consider them consecutive -//1.0 is a wild guess -#define MAX_PTS_DIFF_FOR_CONSECUTIVE 1.0 - -//returns the first pts found within TIME_STAMP_PROBE_LEN bytes after stream_pos in demuxer's stream. -//if no pts is found or an error occurs, -1.0 is returned. -//Packs are freed. -static float read_first_mpeg_pts_at_position(demuxer_t* demuxer, int64_t stream_pos) -{ - stream_t *s = demuxer->stream; - mpg_demuxer_t *mpg_d = demuxer->priv; - float pts = -1.0; //the pts to return; - float found_pts1; //the most recently found pts - float found_pts2; //the pts found before found_pts1 - float found_pts3; //the pts found before found_pts2 - int found = 0; - - if(!mpg_d || stream_pos < 0) - return pts; - - found_pts3 = found_pts2 = found_pts1 = mpg_d->last_pts; - stream_seek(s, stream_pos); - - //We look for pts. - //However, we do not stop at the first found one, as timestamps may reset - //Therefore, we seek until we found three consecutive - //pts within MAX_PTS_DIFF_FOR_CONSECUTIVE. - - while(found<3 && !s->eof - && (fabsf(found_pts2-found_pts1) < MAX_PTS_DIFF_FOR_CONSECUTIVE) - && (fabsf(found_pts3-found_pts2) < MAX_PTS_DIFF_FOR_CONSECUTIVE) - && (stream_tell(s) < stream_pos + TIMESTAMP_PROBE_LEN) - && ds_fill_buffer(demuxer->video)) - { - if(mpg_d->last_pts != found_pts1) - { - if(!found) - found_pts3 = found_pts2 = found_pts1 = mpg_d->last_pts; //the most recently found pts - else - { - found_pts3 = found_pts2; - found_pts2 = found_pts1; - found_pts1 = mpg_d->last_pts; - } - found++; - } - } - - if(found == 3) pts = found_pts3; - - //clean up from searching of first pts; - demux_flush(demuxer); - - return pts; -} - -/// Open an mpg physical stream -static demuxer_t* demux_mpg_open(demuxer_t* demuxer) { - stream_t *s = demuxer->stream; - mpg_demuxer_t* mpg_d; - - if (!ds_fill_buffer(demuxer->video)) return 0; - mpg_d = calloc(1,sizeof(mpg_demuxer_t)); - if(mpg_d) - { - demuxer->priv = mpg_d; - mpg_d->last_pts = -1.0; - mpg_d->first_pts = -1.0; - - //if seeking is allowed set has_valid_timestamps if appropriate - if(demuxer->seekable - && (demuxer->stream->type == STREAMTYPE_FILE - || demuxer->stream->type == STREAMTYPE_VCD) - && demuxer->movi_start != demuxer-> movi_end - ) - { - //We seek to the beginning of the stream, to somewhere in the - //middle, and to the end of the stream, while remembering the pts - //at each of the three positions. With these pts, we check whether - //or not the pts are "linear enough" to justify seeking by the pts - //of the stream - - //The position where the stream is now - int64_t pos = stream_tell(s); - float first_pts = read_first_mpeg_pts_at_position(demuxer, demuxer->movi_start); - if(first_pts != -1.0) - { - float middle_pts = read_first_mpeg_pts_at_position(demuxer, (demuxer->movi_end + demuxer->movi_start)/2); - if(middle_pts != -1.0) - { - float final_pts = read_first_mpeg_pts_at_position(demuxer, demuxer->movi_end - TIMESTAMP_PROBE_LEN); - if(final_pts != -1.0) - { - // found proper first, middle, and final pts. - float proportion = (middle_pts-first_pts==0) ? -1 : (final_pts-middle_pts)/(middle_pts-first_pts); - // if they are linear enough set has_valid_timestamps - if((0.5 < proportion) && (proportion < 2)) - { - mpg_d->first_pts = first_pts; - mpg_d->first_to_final_pts_len = final_pts - first_pts; - mpg_d->has_valid_timestamps = 1; - } - } - } - } - - //Cleaning up from seeking in stream - demuxer->stream->eof=0; - demuxer->video->eof=0; - demuxer->audio->eof=0; - - stream_seek(s,pos); - ds_fill_buffer(demuxer->video); - } // if ( demuxer->seekable ) - } // if ( mpg_d ) - return demuxer; -} - -static void demux_close_mpg(demuxer_t* demuxer) { - mpg_demuxer_t* mpg_d = demuxer->priv; - free(mpg_d); -} - - -static unsigned long long read_mpeg_timestamp(stream_t *s,int c){ - unsigned int d,e; - unsigned long long 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=(((uint64_t)((c>>1)&7))<<30)|((d>>1)<<15)|(e>>1); - mp_dbg(MSGT_DEMUX,MSGL_DBG3," pts {%llu}",pts); - return pts; -} - -static void new_audio_stream(demuxer_t *demux, int aid){ - if(!demux->a_streams[aid]){ - mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demux->priv; - sh_audio_t* sh_a; - new_sh_audio(demux,aid); - sh_a = (sh_audio_t*)demux->a_streams[aid]; - sh_a->needs_parsing = 1; - switch(aid & 0xE0){ // 1110 0000 b (high 3 bit: type low 5: id) - case 0x00: sh_a->format=0x50;break; // mpeg - case 0xA0: sh_a->format=0x10001;break; // dvd pcm - case 0x80: if((aid & 0xF8) == 0x88) sh_a->format=0x2001;//dts - else sh_a->format=0x2000;break; // ac3 - } - //evo files - if((aid & 0xC0) == 0xC0) sh_a->format=0x2000; - else if(aid >= 0x98 && aid <= 0x9f) sh_a->format=0x2001; - if (mpg_d) mpg_d->a_stream_ids[mpg_d->num_a_streams++] = aid; - mp_set_audio_codec_from_tag(sh_a); - } - if(demux->audio->id==-1) demux->audio->id=aid; -} - -static void dvdpcm_header(sh_audio_t *sh) -{ - if (sh->format != 0x10001) - return; - - WAVEFORMATEX *wf = calloc(sizeof(*wf), 1); - - if(sh->codecdata_len==3){ - // we have LPCM header: - unsigned char h=sh->codecdata[1]; - wf->nChannels=1+(h&7); - switch((h>>4)&3){ - case 0: wf->nSamplesPerSec=48000;break; - case 1: wf->nSamplesPerSec=96000;break; - case 2: wf->nSamplesPerSec=44100;break; - case 3: wf->nSamplesPerSec=32000;break; - } - switch ((h >> 6) & 3) { - case 0: - wf->wBitsPerSample = 2 * 8; - break; - case 1: - mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Samples of this format are needed to improve support. Please contact the developers.\n"); - wf->nAvgBytesPerSec = wf->nChannels * wf->nSamplesPerSec * 5 / 2; - case 2: - wf->wBitsPerSample = 3 * 8; - break; - default: - wf->wBitsPerSample = 2 * 8; - } - } else { - // use defaults: - wf->nChannels=2; - wf->nSamplesPerSec=48000; - wf->wBitsPerSample = 2 * 8; - } - if (!wf->nAvgBytesPerSec) - wf->nAvgBytesPerSec = wf->wBitsPerSample / 8 * wf->nChannels * wf->nSamplesPerSec; - if (wf->wBitsPerSample == 16) - sh->format = 0x20776172; // 'raw ', pcm_s16be - sh->wf = wf; -} - -static int demux_mpg_read_packet(demuxer_t *demux,int id){ - int d av_unused; - int len; - int set_pts=0; // !=0 iff pts has been set to a proper value - unsigned char c=0; - unsigned long long pts=0; - unsigned long long dts av_unused = 0; - int l; - int pes_ext2_subid=-1; - double stream_pts = MP_NOPTS_VALUE; - demux_stream_t *ds=NULL; - demux_packet_t* dp; - mpg_demuxer_t *priv = (mpg_demuxer_t *) demux->priv; - - 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) && id != 0x1FD) 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; - - if(id==0x1BC) { - parse_psm(demux, len); - return 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); - set_pts=1; - 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}"); - else set_pts = 1; - dts=read_mpeg_timestamp(demux->stream,c); - len-=4+1+4; - } else - if((c>>6)==2){ - int pts_flags; - int hdrlen; - int parse_ext2; - // System-2 (.VOB) stream: - c=stream_read_char(demux->stream); - pts_flags=c>>6; - parse_ext2 = (id == 0x1FD) && ((c & 0x3F) == 1); - 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 && hdrlen>=5){ - c=stream_read_char(demux->stream); - pts=read_mpeg_timestamp(demux->stream,c); - set_pts=1; - len-=5;hdrlen-=5; - } else - if(pts_flags==3 && hdrlen>=10){ - c=stream_read_char(demux->stream); - pts=read_mpeg_timestamp(demux->stream,c); - set_pts=1; - c=stream_read_char(demux->stream); - dts=read_mpeg_timestamp(demux->stream,c); - len-=10;hdrlen-=10; - } - len-=hdrlen; - if(parse_ext2 && hdrlen>=3) { - c=stream_read_char(demux->stream); - hdrlen--; - - if((c & 0x0F) != 0x0F) { - mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: pes_extension_flag2 not set, discarding pes packet\n"); - return -1; - } - if(c & 0x80) { //pes_private_data_flag - if(hdrlen<16) { - mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: not enough pes_private_data bytes: %d < 16, discarding pes packet\n", hdrlen); - return -1; - } - stream_skip(demux->stream, 16); - hdrlen-=16; - } - if(c & 0x40) { //pack_header_field_flag - int l = stream_read_char(demux->stream); - if(l < 0) //couldn't read from the stream? - return -1; - hdrlen--; - if(l < 0 || hdrlen < l) { - mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: not enough pack_header bytes: hdrlen: %d < skip: %d, discarding pes packet\n", - hdrlen, l); - return -1; - } - stream_skip(demux->stream, l); - hdrlen-=l; - } - if(c & 0x20) { //program_packet_sequence_counter_flag - if(hdrlen < 2) { - mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: not enough program_packet bytes: hdrlen: %d, discarding pes packet\n", hdrlen); - return -1; - } - stream_skip(demux->stream, 2); - hdrlen-=2; - } - if(c & 0x10) { - //STD - stream_skip(demux->stream, 2); - hdrlen-=2; - } - c=stream_read_char(demux->stream); //pes_extension2 flag - hdrlen--; - if(c!=0x81) { mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: unknown pes_extension2 format, len is > 1 \n"); return -1;} - c=stream_read_char(demux->stream); //pes_extension2 payload === substream id - hdrlen--; - if(c<0x55 || c>0x5F) { mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: unknown vc1 substream_id: 0x%x \n", c); return -1;} - pes_ext2_subid=c; - } - if(hdrlen>0) - stream_skip(demux->stream,hdrlen); // skip header and stuffing bytes - - if(id==0x1FD && pes_ext2_subid!=-1) { - //==== EVO VC1 STREAMS ===// - if(!demux->v_streams[pes_ext2_subid]) new_sh_video(demux,pes_ext2_subid); - if(demux->video->id==-1) demux->video->id=pes_ext2_subid; - if(demux->video->id==pes_ext2_subid){ - ds=demux->video; - if(!ds->sh) ds->sh=demux->v_streams[pes_ext2_subid]; - if(priv && ds->sh) { - sh_video_t *sh = (sh_video_t *)ds->sh; - sh->format = mmioFOURCC('W', 'V', 'C', '1'); - mp_set_video_codec_from_tag(sh); - } - } - } - //============== DVD Audio sub-stream ====================== - if(id==0x1BD){ - int aid, rawa52 = 0; - int64_t tmppos; - unsigned int tmp; - - tmppos = stream_tell(demux->stream); - tmp = stream_read_word(demux->stream); - stream_seek(demux->stream, tmppos); - /// vdr stores A52 without the 4 header bytes, so we have to check this condition first - if(tmp == 0x0B77) { - aid = 128; - rawa52 = 1; - } - else { - aid=stream_read_char(demux->stream);--len; - if(len<3) return -1; // invalid audio packet - } - - // AID: - // 0x20..0x3F subtitle - // 0x80..0x87 and 0xC0..0xCF AC3 audio - // 0x88..0x8F and 0x98..0x9F DTS audio - // 0xA0..0xBF PCM audio - - if((aid & 0xE0) == 0x20){ - // subtitle: - aid&=0x1F; - - if(!demux->s_streams[aid]){ - sh_sub_t *sh = new_sh_sub(demux, aid); - if (sh) sh->gsh->codec = "dvd_subtitle_mpg"; - mp_msg(MSGT_DEMUX,MSGL_V,"==> Found subtitle: %d\n",aid); - } - - if(demux->sub->id > -1) - demux->sub->id &= 0x1F; - if(!demux->opts->sub_lang && demux->sub->id == -1) - demux->sub->id = aid; - if(demux->sub->id==aid){ - ds=demux->sub; - } - } else if((aid >= 0x80 && aid <= 0x8F) || (aid >= 0x98 && aid <= 0xAF) || (aid >= 0xC0 && aid <= 0xCF)) { - -// aid=128+(aid&0x7F); - // aid=0x80..0xBF - new_audio_stream(demux, 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: - if(!rawa52) { - c=stream_read_char(demux->stream);//num of frames - type=stream_read_char(demux->stream);//startpos hi - type=(type<<8)|stream_read_char(demux->stream);//startpos lo -// printf("\r[%02X][%04X]",c,type); - len-=3; - } - if((aid&0xE0)==0xA0 && len>=3){ - unsigned char* hdr; - // save audio header as codecdata! - if(!((sh_audio_t*)(ds->sh))->codecdata_len){ - ((sh_audio_t*)(ds->sh))->codecdata=malloc(3); - ((sh_audio_t*)(ds->sh))->codecdata_len=3; - } - hdr=((sh_audio_t*)(ds->sh))->codecdata; - // read LPCM header: - // emphasis[1], mute[1], rvd[1], frame number[5]: - hdr[0]=stream_read_char(demux->stream); -// printf(" [%01X:%02d]",c>>5,c&31); - // quantization[2],freq[2],rvd[1],channels[3] - hdr[1]=stream_read_char(demux->stream); -// printf("[%01X:%01X] ",c>>4,c&15); - // dynamic range control (0x80=off): - hdr[2]=stream_read_char(demux->stream); -// printf("[%02X] ",c); - len-=3; - if(len<=0) mp_msg(MSGT_DEMUX,MSGL_V,"End of packet while searching for PCM header\n"); - dvdpcm_header((sh_audio_t*)(ds->sh)); - mp_set_audio_codec_from_tag((sh_audio_t*)(ds->sh)); - } -// printf(" \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; - new_audio_stream(demux, aid); - if(demux->audio->id==aid){ - ds=demux->audio; - if(!ds->sh) ds->sh=demux->a_streams[aid]; - if(priv && ds->sh) { - sh_audio_t *sh = (sh_audio_t *)ds->sh; - if(priv->es_map[id - 0x1B0]) - sh->format = priv->es_map[id - 0x1B0]; - mp_dbg(MSGT_DEMUX,MSGL_DBG2,"ASSIGNED TO STREAM %d CODEC %x\n", id, priv->es_map[id - 0x1B0]); - dvdpcm_header(sh); - mp_set_audio_codec_from_tag(sh); - } - } - } 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(priv && ds->sh) { - sh_video_t *sh = (sh_video_t *)ds->sh; - if(priv->es_map[id - 0x1B0]) { - sh->format = priv->es_map[id - 0x1B0]; - mp_set_video_codec_from_tag(sh); - mp_dbg(MSGT_DEMUX,MSGL_DBG2,"ASSIGNED TO STREAM %d CODEC %x\n", id, priv->es_map[id - 0x1B0]); - } - } - } - } - - 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); - - dp=new_demux_packet(len); - if(!dp) { - mp_dbg(MSGT_DEMUX,MSGL_ERR,"DEMUX_MPG ERROR: couldn't create demux_packet(%d bytes)\n",len); - stream_skip(demux->stream,len); - return 0; - } - l = stream_read(demux->stream,dp->buffer,len); - if(l<len) - resize_demux_packet(dp, l); - len = l; - if(set_pts) - dp->pts=pts/90000.0f; - dp->pos=demux->filepos; - /* - workaround: - set dp->stream_pts only when feeding the video stream, or strangely interleaved files - (such as SWIII) will show strange alternations in the stream time, wildly going - back and forth - */ - if(ds == demux->video && stream_control(demux->stream, STREAM_CTRL_GET_CURRENT_TIME,(void *)&stream_pts)!=STREAM_UNSUPPORTED) - dp->stream_pts = stream_pts; - ds_add_packet(ds,dp); - if (demux->priv && set_pts) ((mpg_demuxer_t*)demux->priv)->last_pts = pts/90000.0f; -// 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; -} - -static int num_elementary_packets100=0; -static int num_elementary_packets101=0; -static int num_elementary_packets12x=0; -static int num_elementary_packets1B6=0; -static int num_elementary_packetsPES=0; -static int num_mpeg12_startcode=0; -static int num_h264_slice=0; //combined slice -static int num_h264_dpa=0; //DPA Slice -static int num_h264_dpb=0; //DPB Slice -static int num_h264_dpc=0; //DPC Slice -static int num_h264_idr=0; //IDR Slice -static int num_h264_sps=0; -static int num_h264_pps=0; - -static int num_mp3audio_packets=0; - -static void clear_stats(void) -{ - num_elementary_packets100=0; - num_elementary_packets101=0; - num_elementary_packets1B6=0; - num_elementary_packets12x=0; - num_elementary_packetsPES=0; - num_mpeg12_startcode=0; - num_h264_slice=0; //combined slice - num_h264_dpa=0; //DPA Slice - num_h264_dpb=0; //DPB Slice - num_h264_dpc=0; //DPC Slice - num_h264_idr=0; //IDR Slice - num_h264_sps=0; - num_h264_pps=0; - num_mp3audio_packets=0; -} - -//assumes demuxer->synced < 2 -static inline void update_stats(int head) -{ - if(head==0x1B6) ++num_elementary_packets1B6; - else if(head==0x1B3 || head==0x1B8) ++num_mpeg12_startcode; - else if(head==0x100) ++num_elementary_packets100; - else if(head==0x101) ++num_elementary_packets101; - else if(head==0x1BD || (0x1C0<=head && head<=0x1EF)) - num_elementary_packetsPES++; - else if(head>=0x120 && head<=0x12F) ++num_elementary_packets12x; - if(head>=0x100 && head<0x1B0) - { - if((head&~0x60) == 0x101) ++num_h264_slice; - else if((head&~0x60) == 0x102) ++num_h264_dpa; - else if((head&~0x60) == 0x103) ++num_h264_dpb; - else if((head&~0x60) == 0x104) ++num_h264_dpc; - else if((head&~0x60) == 0x105 && head != 0x105) ++num_h264_idr; - else if((head&~0x60) == 0x107 && head != 0x107) ++num_h264_sps; - else if((head&~0x60) == 0x108 && head != 0x108) ++num_h264_pps; - } -} - -static int demux_mpg_probe(demuxer_t *demuxer) { - int pes av_unused = 1; - int tmp; - int64_t tmppos; - int file_format = DEMUXER_TYPE_UNKNOWN; - - tmppos=stream_tell(demuxer->stream); - tmp=stream_read_dword(demuxer->stream); - if(tmp==0x1E0 || tmp==0x1C0) { - tmp=stream_read_word(demuxer->stream); - if(tmp>1 && tmp<=2048) pes=0; // demuxer->synced=3; // PES... - } - stream_seek(demuxer->stream,tmppos); - - clear_stats(); - - if(demux_mpg_open(demuxer)) - file_format=DEMUXER_TYPE_MPEG_PS; - else { - mp_msg(MSGT_DEMUX,MSGL_V,"MPEG packet stats: p100: %d p101: %d p1B6: %d p12x: %d sli: %d a: %d b: %d c: %d idr: %d sps: %d pps: %d PES: %d MP3: %d, synced: %d\n", - num_elementary_packets100,num_elementary_packets101, - num_elementary_packets1B6,num_elementary_packets12x, - num_h264_slice, num_h264_dpa, - num_h264_dpb, num_h264_dpc=0, - num_h264_idr, num_h264_sps=0, - num_h264_pps, - num_elementary_packetsPES,num_mp3audio_packets, demuxer->synced); - - //MPEG packet stats: p100: 458 p101: 458 PES: 0 MP3: 1103 (.m2v) - if(num_mp3audio_packets>50 && num_mp3audio_packets>2*num_elementary_packets100 - && abs(num_elementary_packets100-num_elementary_packets101)>2) - return file_format; - - // some hack to get meaningfull error messages to our unhappy users: - if(num_mpeg12_startcode>=2 && num_elementary_packets100>=2 && num_elementary_packets101>=2 && - abs(num_elementary_packets101+8-num_elementary_packets100)<16) { - if(num_elementary_packetsPES>=4 && num_elementary_packetsPES>=num_elementary_packets100-4) { - return file_format; - } - file_format=DEMUXER_TYPE_MPEG_ES; // <-- hack is here :) - } else - // fuzzy mpeg4-es detection. do NOT enable without heavy testing of mpeg formats detection! - if(num_elementary_packets1B6>3 && num_elementary_packets12x>=1 && - num_elementary_packetsPES==0 && num_elementary_packets100<=num_elementary_packets12x && - demuxer->synced<2) { - file_format=DEMUXER_TYPE_MPEG4_ES; - } else - // fuzzy h264-es detection. do NOT enable without heavy testing of mpeg formats detection! - if((num_h264_slice>3 || (num_h264_dpa>3 && num_h264_dpb>3 && num_h264_dpc>3)) && - /* FIXME num_h264_sps>=1 && */ num_h264_pps>=1 && num_h264_idr>=1 && - num_elementary_packets1B6==0 && num_elementary_packetsPES==0 && - demuxer->synced<2) { - file_format=DEMUXER_TYPE_H264_ES; - } else - { - if(demuxer->synced==2) - mp_msg(MSGT_DEMUXER, MSGL_ERR, "MPEG: %s", - mp_gtext("Missing video stream!? Contact the author, it may be a bug :(\n")); - else - mp_tmsg(MSGT_DEMUXER,MSGL_V,"Not MPEG System Stream format... (maybe Transport Stream?)\n"); - } - } - //FIXME this shouldn't be necessary - stream_seek(demuxer->stream,tmppos); - return file_format; -} - -static int demux_mpg_es_fill_buffer(demuxer_t *demux, demux_stream_t *ds){ - // 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; -} - -/** - * \brief discard until 0x100 header and return a filled buffer - * \param b buffer-end pointer - * \param pos current pos in stream, negative since b points to end of buffer - * \param s stream to read from - * \return new position, differs from original pos when eof hit and thus - * b was modified to point to the new end of buffer - */ -static int find_end(unsigned char **b, int pos, stream_t *s) { - register int state = 0xffffffff; - unsigned char *buf = *b; - int start = pos; - int read, unused; - // search already read part - while (state != 0x100 && pos) { - state = state << 8 | buf[pos++]; - } - // continue search in stream - while (state != 0x100) { - register int c = stream_read_char(s); - if (c < 0) break; - state = state << 8 | c; - } - // modify previous header (from 0x1bc or 0x1bf to 0x100) - buf[start++] = 0; - // copy remaining buffer part to current pos - memmove(&buf[start], &buf[pos], -pos); - unused = start + -pos; // -unused bytes in buffer - read = stream_read(s, &buf[unused], -unused); - unused += read; - // fix buffer so it ends at pos == 0 (eof case) - *b = &buf[unused]; - start -= unused; - return start; -} - -/** - * This format usually uses an insane bitrate, which makes this function - * performance-critical! - * Be sure to benchmark any changes with different compiler versions. - */ -static int demux_mpg_gxf_fill_buffer(demuxer_t *demux, demux_stream_t *ds) { - demux_packet_t *pack; - int len; - demux->filepos = stream_tell(demux->stream); - pack = new_demux_packet(STREAM_BUFFER_SIZE); - len = stream_read(demux->stream, pack->buffer, STREAM_BUFFER_SIZE); - if (len <= 0) - { - free_demux_packet(pack); - return 0; - } - { - register uint32_t state = (uint32_t)(uintptr_t)demux->priv; - register int pos = -len; - unsigned char *buf = &pack->buffer[len]; - do { - state = state << 8 | buf[pos]; - if (unlikely((state | 3) == 0x1bf)) - pos = find_end(&buf, pos, demux->stream); - } while (++pos < 0); - demux->priv = (void *)(uintptr_t)state; - len = buf - pack->buffer; - } - if (len < STREAM_BUFFER_SIZE) - resize_demux_packet(pack, len); - ds_add_packet(ds, pack); - return 1; -} - -static int demux_mpg_fill_buffer(demuxer_t *demux, demux_stream_t *ds) -{ -unsigned int head=0; -int skipped=0; -int max_packs=256; // 512kbyte -int ret=0; - -// System stream -do{ - demux->filepos=stream_tell(demux->stream); - //lame workaround: this is needed to show the progress bar when playing dvdnav:// - //(ths poor guy doesn't know teh length of the stream at startup) - demux->movi_end = demux->stream->end_pos; - 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; - if(mp_check_mp3_header(head)) ++num_mp3audio_packets; - ++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; //else -// if(head==0x1BD || (head>=0x1C0 && head<=0x1EF)) demux->synced=3; // PES? - } 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%"PRIX64" (%"PRId64")!\n",(int64_t)demux->filepos,(int64_t)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_tmsg(MSGT_DEMUX,MSGL_ERR,"demux: File doesn't contain the selected audio or video stream.\n"); - return 0; - } - if(demux->synced==3) demux->synced=(ret==1)?2:0; // PES detect - } else { - update_stats(head); - if(head>=0x100 && head<0x1B0) - mp_msg(MSGT_DEMUX,MSGL_DBG3,"Opps... elementary video packet found: %03X\n",head); - else if((head>=0x1C0 && head<0x1F0) || head==0x1BD) - mp_msg(MSGT_DEMUX,MSGL_DBG3,"Opps... PES packet found: %03X\n",head); - - 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; - } - if(num_mp3audio_packets>100 && num_elementary_packets100<10){ - mp_msg(MSGT_DEMUX,MSGL_V,"sync_mpeg_ps: seems to be MP3 stream...\n"); - demux->stream->eof=1; - break; - } - } -} 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; -} - -static void demux_seek_mpg(demuxer_t *demuxer, float rel_seek_secs, - float audio_delay, 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; - mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demuxer->priv; - int precision = 1; - float oldpts = 0; - int64_t oldpos = demuxer->filepos; - float newpts = 0; - int64_t newpos = (flags & SEEK_ABSOLUTE) ? demuxer->movi_start : oldpos; - - if(mpg_d) - oldpts = mpg_d->last_pts; - newpts = (flags & SEEK_ABSOLUTE) ? 0.0 : oldpts; - //================= seek in MPEG ========================== - //calculate the pts to seek to - if(flags & SEEK_FACTOR) { - if (mpg_d && mpg_d->first_to_final_pts_len > 0.0) - newpts += mpg_d->first_to_final_pts_len * rel_seek_secs; - else - newpts += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) * oldpts / oldpos; - } else - newpts += rel_seek_secs; - if (newpts < 0) newpts = 0; - - if(flags&SEEK_FACTOR){ - // float seek 0..1 - newpos+=(demuxer->movi_end-demuxer->movi_start)*rel_seek_secs; - } else { - // time seek (secs) - if (mpg_d && mpg_d->has_valid_timestamps) { - if (mpg_d->first_to_final_pts_len > 0.0) - newpos += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) / mpg_d->first_to_final_pts_len; - else if (oldpts > 0.0) - newpos += rel_seek_secs * (oldpos - demuxer->movi_start) / oldpts; - } else if(!sh_video || !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; - } - - while (1) { - if(newpos<demuxer->movi_start){ - if(demuxer->stream->type!=STREAMTYPE_VCD) demuxer->movi_start=0; // for VCD - if(newpos<demuxer->movi_start) newpos=demuxer->movi_start; - } - - 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); - } - - 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; - } - } - if(!sh_video) break; - i=sync_video_packet(d_video); - if(sh_video->format == mmioFOURCC('W', 'V', 'C', '1')) { - if(i==0x10E || i==0x10F) //entry point or sequence header - break; - } else - if(sh_video->format == 0x10000004) { //mpeg4 - if(i==0x1B6) { //vop (frame) startcode - int pos = videobuf_len; - if(!read_video_packet(d_video)) break; // EOF - if((videobuffer[pos+4] & 0x3F) == 0) break; //I-frame - } - } else if(sh_video->format == 0x10000005){ //h264 - if((i & ~0x60) == 0x105) break; - } else { //default mpeg1/2 - if(i==0x1B3 || i==0x1B8) break; // found it! - } - if(!i || !skip_video_packet(d_video)) break; // EOF? - } - if(!mpg_d) - break; - if (!precision || abs(newpts - mpg_d->last_pts) < 0.5 || (mpg_d->last_pts == oldpts)) break; - if ((newpos - oldpos) * (mpg_d->last_pts - oldpts) < 0) { // invalid timestamps - mpg_d->has_valid_timestamps = 0; - break; - } - precision--; - //prepare another seek because we are off by more than 0.5s - if(mpg_d) { - newpos += (newpts - mpg_d->last_pts) * (newpos - oldpos) / (mpg_d->last_pts - oldpts); - demux_flush(demuxer); - demuxer->stream->eof=0; // clear eof flag - d_video->eof=0; - d_audio->eof=0; - } - } -} - -static int demux_mpg_control(demuxer_t *demuxer, int cmd, void *arg) -{ - mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demuxer->priv; - - switch(cmd) { - case DEMUXER_CTRL_GET_TIME_LENGTH: - if(stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, arg) != STREAM_UNSUPPORTED) { - mp_msg(MSGT_DEMUXER,MSGL_DBG2,"\r\nDEMUX_MPG_CTRL, (%.3f)\r\n", *((double*)arg)); - return DEMUXER_CTRL_GUESS; - } - if (mpg_d && mpg_d->has_valid_timestamps) { - *((double *)arg)=(double)mpg_d->first_to_final_pts_len; - return DEMUXER_CTRL_OK; - } - return DEMUXER_CTRL_DONTKNOW; - - case DEMUXER_CTRL_GET_START_TIME: - if (mpg_d && mpg_d->has_valid_timestamps && mpg_d->first_to_final_pts_len > 0.0) { - *((float *)arg)=mpg_d->first_pts; - return DEMUXER_CTRL_OK; - } - return DEMUXER_CTRL_DONTKNOW; - - case DEMUXER_CTRL_SWITCH_AUDIO: - if(! (mpg_d && mpg_d->num_a_streams > 1 && demuxer->audio && demuxer->audio->sh)) - return DEMUXER_CTRL_NOTIMPL; - else { - demux_stream_t *d_audio = demuxer->audio; - sh_audio_t *sh_audio = d_audio->sh; - sh_audio_t *sh_a = sh_audio; - int i; - if(!sh_audio) - return DEMUXER_CTRL_NOTIMPL; - if (*((int*)arg) < 0) - { - for (i = 0; i < mpg_d->num_a_streams; i++) { - if (d_audio->id == mpg_d->a_stream_ids[i]) break; - } - i = (i+1) % mpg_d->num_a_streams; - sh_a = (sh_audio_t*)demuxer->a_streams[mpg_d->a_stream_ids[i]]; - } - else { - for (i = 0; i < mpg_d->num_a_streams; i++) - if (*((int*)arg) == mpg_d->a_stream_ids[i]) break; - if (i < mpg_d->num_a_streams) - sh_a = (sh_audio_t*)demuxer->a_streams[*((int*)arg)]; - } - if (i < mpg_d->num_a_streams && d_audio->id != mpg_d->a_stream_ids[i]) { - d_audio->id = mpg_d->a_stream_ids[i]; - d_audio->sh = sh_a; - ds_free_packs(d_audio); - } - } - *((int*)arg) = demuxer->audio->id; - return DEMUXER_CTRL_OK; - - default: - return DEMUXER_CTRL_NOTIMPL; - } -} - - -static int demux_mpg_pes_probe(demuxer_t *demuxer) { - demuxer->synced = 3; - return (demux_mpg_probe(demuxer) == DEMUXER_TYPE_MPEG_PS) ? DEMUXER_TYPE_MPEG_PES : 0; -} - - -static demuxer_t* demux_mpg_es_open(demuxer_t* demuxer) -{ - sh_video_t *sh_video=NULL; - - demuxer->audio->sh = NULL; // ES streams has no audio channel - demuxer->video->sh = new_sh_video(demuxer,0); // create dummy video stream header, id=0 - sh_video=demuxer->video->sh;sh_video->ds=demuxer->video; - - demuxer->ts_resets_possible = true; - - return demuxer; -} - -static demuxer_t *demux_mpg_gxf_open(demuxer_t *demuxer) { - demuxer->audio->sh = NULL; - demuxer->video->sh = new_sh_video(demuxer,0); - ((sh_video_t *)demuxer->video->sh)->ds = demuxer->video; - demuxer->priv = (void *) 0xffffffff; - - demuxer->ts_resets_possible = true; - - return demuxer; -} - -static demuxer_t* demux_mpg_ps_open(demuxer_t* demuxer) -{ - sh_audio_t *sh_audio=NULL; - sh_video_t *sh_video=NULL; - - sh_video=demuxer->video->sh;sh_video->ds=demuxer->video; - - demuxer->ts_resets_possible = true; - - if(demuxer->audio->id!=-2) { - if(!ds_fill_buffer(demuxer->audio)){ - mp_msg(MSGT_DEMUXER, MSGL_INFO, "MPEG: %s", - mp_gtext("No audio stream found -> no sound.\n")); - demuxer->audio->sh=NULL; - } else { - sh_audio=demuxer->audio->sh;sh_audio->ds=demuxer->audio; - } - } - - if(!sh_video->format && ps_probe > 0) { - int head; - int64_t pos = stream_tell(demuxer->stream); - - clear_stats(); - do { - head=sync_video_packet(demuxer->video); - if(!head) break; - update_stats(head); - skip_video_packet(demuxer->video); - } while(stream_tell(demuxer->stream) < pos + ps_probe && !demuxer->stream->eof); - - ds_free_packs(demuxer->video); - demuxer->stream->eof=0; - stream_seek(demuxer->stream, pos); - mp_msg(MSGT_DEMUX,MSGL_INFO,"MPEG packet stats: p100: %d p101: %d p1B6: %d p12x: %d sli: %d a: %d b: %d c: %d idr: %d sps: %d pps: %d\n", - num_elementary_packets100, num_elementary_packets101, - num_elementary_packets1B6, num_elementary_packets12x, - num_h264_slice, num_h264_dpa, num_h264_dpb, num_h264_dpc, - num_h264_idr, num_h264_sps, num_h264_pps); - - if(num_elementary_packets1B6>3 && num_elementary_packets12x>=1 && - num_elementary_packets100<=num_elementary_packets12x) - sh_video->format = 0x10000004; - else if((num_h264_slice>3 || (num_h264_dpa>3 && num_h264_dpb>3 && num_h264_dpc>3)) && - num_h264_sps>=1 && num_h264_pps>=1 && num_h264_idr>=1 && - num_elementary_packets1B6==0) - sh_video->format = 0x10000005; - else sh_video->format = 0x10000002; - mp_set_video_codec_from_tag(sh_video); - } - - return demuxer; -} - - -const demuxer_desc_t demuxer_desc_mpeg_ps = { - "MPEG PS demuxer", - "mpegps", - "MPEG-PS", - "Arpi?", - "Mpeg", - DEMUXER_TYPE_MPEG_PS, - 0, // unsafe autodetect - demux_mpg_probe, - demux_mpg_fill_buffer, - demux_mpg_ps_open, - demux_close_mpg, - demux_seek_mpg, - demux_mpg_control, -}; - - -const demuxer_desc_t demuxer_desc_mpeg_pes = { - "MPEG PES demuxer", - "mpegpes", - "MPEG-PES", - "Arpi?", - "Mpeg", - DEMUXER_TYPE_MPEG_PES, - 0, // unsafe autodetect - demux_mpg_pes_probe, - demux_mpg_fill_buffer, - demux_mpg_ps_open, - demux_close_mpg, - demux_seek_mpg, - demux_mpg_control, -}; - - -const demuxer_desc_t demuxer_desc_mpeg_gxf = { - "MPEG ES in GXF demuxer", - "mpeggxf", - "MPEG-ES in GXF", - "Reimar Doeffinger", - "Mpeg", - DEMUXER_TYPE_MPEG_GXF, - 0, // hack autodetection - NULL, - demux_mpg_gxf_fill_buffer, - demux_mpg_gxf_open, - NULL, - NULL, - NULL -}; - -const demuxer_desc_t demuxer_desc_mpeg_es = { - "MPEG ES demuxer", - "mpeges", - "MPEG-ES", - "Arpi?", - "Mpeg", - DEMUXER_TYPE_MPEG_ES, - 0, // hack autodetection - NULL, - demux_mpg_es_fill_buffer, - demux_mpg_es_open, - demux_close_mpg, - demux_seek_mpg, - demux_mpg_control, -}; - - -const demuxer_desc_t demuxer_desc_mpeg4_es = { - "MPEG4 ES demuxer", - "mpeg4es", - "MPEG-ES", - "Arpi?", - "Mpeg", - DEMUXER_TYPE_MPEG4_ES, - 0, // hack autodetection - NULL, - demux_mpg_es_fill_buffer, - demux_mpg_es_open, - demux_close_mpg, - demux_seek_mpg, - demux_mpg_control, -}; - - -const demuxer_desc_t demuxer_desc_h264_es = { - "H.264 ES demuxer", - "h264es", - "H264-ES", - "Arpi?", - "Mpeg", - DEMUXER_TYPE_H264_ES, - 0, // hack autodetection - NULL, - demux_mpg_es_fill_buffer, - demux_mpg_es_open, - demux_close_mpg, - demux_seek_mpg, - demux_mpg_control, -}; diff --git a/demux/demux_ts.c b/demux/demux_ts.c deleted file mode 100644 index a16891907d..0000000000 --- a/demux/demux_ts.c +++ /dev/null @@ -1,3532 +0,0 @@ -/* - * Demultiplexer for MPEG2 Transport Streams. - * - * Written by Nico <nsabbi@libero.it> - * Kind feedback is appreciated; 'sucks' and alike is not. - * Originally based on demux_pva.c written by Matteo Giani and FFmpeg (libavformat) sources - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "config.h" -#include "core/mp_msg.h" -#include "core/options.h" - -#include "audio/decode/dec_audio.h" -#include "stream/stream.h" -#include "demux.h" -#include "parse_es.h" -#include "stheader.h" -#include "ms_hdr.h" -#include "mpeg_hdr.h" -#include "demux_ts.h" - -#define TS_PH_PACKET_SIZE 192 -#define TS_FEC_PACKET_SIZE 204 -#define TS_PACKET_SIZE 188 -#define NB_PID_MAX 8192 - -#define MAX_HEADER_SIZE 6 /* enough for PES header + length */ -#define MAX_CHECK_SIZE 65535 -#define NUM_CONSECUTIVE_TS_PACKETS 32 -#define NUM_CONSECUTIVE_AUDIO_PACKETS 348 -#define MAX_A52_FRAME_SIZE 3840 - -#ifndef SIZE_MAX -#define SIZE_MAX ((size_t)-1) -#endif - -#define TYPE_AUDIO 1 -#define TYPE_VIDEO 2 -#define TYPE_SUB 3 - -int ts_prog; -int ts_keep_broken=0; -int64_t ts_probe = 0; -int audio_substream_id = -1; - -typedef enum -{ - UNKNOWN = -1, - VIDEO_MPEG1 = 0x10000001, - VIDEO_MPEG2 = 0x10000002, - VIDEO_MPEG4 = 0x10000004, - VIDEO_H264 = 0x10000005, - VIDEO_AVC = mmioFOURCC('a', 'v', 'c', '1'), - VIDEO_DIRAC = mmioFOURCC('d', 'r', 'a', 'c'), - VIDEO_VC1 = mmioFOURCC('W', 'V', 'C', '1'), - AUDIO_MP2 = 0x50, - AUDIO_A52 = 0x2000, - AUDIO_DTS = 0x2001, - AUDIO_LPCM_BE = 0x10001, - AUDIO_AAC = mmioFOURCC('M', 'P', '4', 'A'), - AUDIO_AAC_LATM = mmioFOURCC('M', 'P', '4', 'L'), - AUDIO_TRUEHD = mmioFOURCC('T', 'R', 'H', 'D'), - AUDIO_S302M = mmioFOURCC('B', 'S', 'S', 'D'), - AUDIO_PCM_BR = mmioFOURCC('B', 'P', 'C', 'M'), - SPU_DVD = 0x3000000, - SPU_DVB = 0x3000001, - SPU_TELETEXT = 0x3000002, - SPU_PGS = 0x3000003, - PES_PRIVATE1 = 0xBD00000, - SL_PES_STREAM = 0xD000000, - SL_SECTION = 0xD100000, - MP4_OD = 0xD200000, -} es_stream_type_t; - -typedef struct { - uint8_t *buffer; - uint16_t buffer_len; -} ts_section_t; - -typedef struct { - int size; - unsigned char *start; - uint16_t payload_size; - es_stream_type_t type, subtype; - double pts, last_pts; - int pid; - char lang[4]; - int last_cc; // last cc code (-1 if first packet) - int is_synced; - ts_section_t section; - uint8_t *extradata; - int extradata_alloc, extradata_len; - struct { - uint8_t au_start, au_end, last_au_end; - } sl; -} ES_stream_t; - -typedef struct { - void *sh; - int id; - int type; -} sh_av_t; - -typedef struct MpegTSContext { - int packet_size; // raw packet size, including FEC if present e.g. 188 bytes - ES_stream_t *pids[NB_PID_MAX]; - sh_av_t streams[NB_PID_MAX]; -} MpegTSContext; - - -typedef struct { - demux_stream_t *ds; - demux_packet_t *pack; - int offset, buffer_size; -} av_fifo_t; - -#define MAX_EXTRADATA_SIZE 64*1024 -typedef struct { - int32_t object_type; //aka codec used - int32_t stream_type; //video, audio etc. - uint8_t buf[MAX_EXTRADATA_SIZE]; - uint16_t buf_size; - uint8_t szm1; -} mp4_decoder_config_t; - -typedef struct { - //flags - uint8_t flags; - uint8_t au_start; - uint8_t au_end; - uint8_t random_accesspoint; - uint8_t random_accesspoint_only; - uint8_t padding; - uint8_t use_ts; - uint8_t idle; - uint8_t duration; - - uint32_t ts_resolution, ocr_resolution; - uint8_t ts_len, ocr_len, au_len, instant_bitrate_len, degr_len, au_seqnum_len, packet_seqnum_len; - uint32_t timescale; - uint16_t au_duration, cts_duration; - uint64_t ocr, dts, cts; -} mp4_sl_config_t; - -typedef struct { - uint16_t id; - uint8_t flags; - mp4_decoder_config_t decoder; - mp4_sl_config_t sl; -} mp4_es_descr_t; - -typedef struct { - uint16_t id; - uint8_t flags; - mp4_es_descr_t *es; - uint16_t es_cnt; -} mp4_od_t; - -typedef struct { - uint8_t skip; - uint8_t table_id; - uint8_t ssi; - uint16_t section_length; - uint16_t ts_id; - uint8_t version_number; - uint8_t curr_next; - uint8_t section_number; - uint8_t last_section_number; - struct pat_progs_t { - uint16_t id; - uint16_t pmt_pid; - } *progs; - uint16_t progs_cnt; - ts_section_t section; -} pat_t; - -typedef struct { - uint16_t progid; - uint8_t skip; - uint8_t table_id; - uint8_t ssi; - uint16_t section_length; - uint8_t version_number; - uint8_t curr_next; - uint8_t section_number; - uint8_t last_section_number; - uint16_t PCR_PID; - uint16_t prog_descr_length; - ts_section_t section; - uint16_t es_cnt; - struct pmt_es_t { - uint16_t pid; - uint32_t type; //it's 8 bit long, but cast to the right type as FOURCC - uint16_t descr_length; - uint8_t format_descriptor[5]; - uint8_t lang[4]; - uint16_t mp4_es_id; - } *es; - mp4_od_t iod, *od; - mp4_es_descr_t *mp4es; - int od_cnt, mp4es_cnt; -} pmt_t; - -typedef struct { - uint64_t size; - float duration; - double first_pts; - double last_pts; -} TS_stream_info; - -typedef struct { - MpegTSContext ts; - int last_pid; - av_fifo_t fifo[3]; //0 for audio, 1 for video, 2 for subs - pat_t pat; - pmt_t *pmt; - uint16_t pmt_cnt; - uint32_t prog; - uint32_t vbitrate; - int keep_broken; - int last_aid; - int last_vid; - int last_sid; - char packet[TS_FEC_PACKET_SIZE]; - TS_stream_info vstr, astr; -} ts_priv_t; - - -typedef struct { - es_stream_type_t type; - ts_section_t section; -} TS_pids_t; - - -static int IS_AUDIO(es_stream_type_t type) -{ - switch (type) { - case AUDIO_MP2: - case AUDIO_A52: - case AUDIO_LPCM_BE: - case AUDIO_PCM_BR: - case AUDIO_AAC: - case AUDIO_AAC_LATM: - case AUDIO_DTS: - case AUDIO_TRUEHD: - case AUDIO_S302M: - return 1; - } - return 0; -} - -static int IS_VIDEO(es_stream_type_t type) -{ - switch (type) { - case VIDEO_MPEG1: - case VIDEO_MPEG2: - case VIDEO_MPEG4: - case VIDEO_H264: - case VIDEO_AVC: - case VIDEO_DIRAC: - case VIDEO_VC1: - return 1; - } - return 0; -} - -static int IS_SUB(es_stream_type_t type) -{ - switch (type) { - case SPU_DVD: - case SPU_DVB: - case SPU_PGS: - case SPU_TELETEXT: - return 1; - } - return 0; -} - -static int ts_parse(demuxer_t *demuxer, ES_stream_t *es, unsigned char *packet, int probe); - -static uint8_t get_packet_size(const unsigned char *buf, int size) -{ - int i; - - if (size < (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS)) - return 0; - - for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) - { - if (buf[i * TS_PACKET_SIZE] != 0x47) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "GET_PACKET_SIZE, pos %d, char: %2x\n", i, buf[i * TS_PACKET_SIZE]); - goto try_fec; - } - } - return TS_PACKET_SIZE; - -try_fec: - for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) - { - if (buf[i * TS_FEC_PACKET_SIZE] != 0x47){ - mp_msg(MSGT_DEMUX, MSGL_DBG2, "GET_PACKET_SIZE, pos %d, char: %2x\n", i, buf[i * TS_PACKET_SIZE]); - goto try_philips; - } - } - return TS_FEC_PACKET_SIZE; - - try_philips: - for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) - { - if (buf[i * TS_PH_PACKET_SIZE] != 0x47) - return 0; - } - return TS_PH_PACKET_SIZE; -} - -static int parse_avc_sps(uint8_t *buf, int len, int *w, int *h); -static uint8_t *pid_lang_from_pmt(ts_priv_t *priv, int pid); - -static void ts_add_stream(demuxer_t * demuxer, ES_stream_t *es) -{ - int i; - ts_priv_t *priv = (ts_priv_t*) demuxer->priv; - - if(priv->ts.streams[es->pid].sh) - return; - - if((IS_AUDIO(es->type) || IS_AUDIO(es->subtype)) && priv->last_aid+1 < MAX_A_STREAMS) - { - sh_audio_t *sh = new_sh_audio_aid(demuxer, priv->last_aid, es->pid); - if(sh) - { - const char *lang = pid_lang_from_pmt(priv, es->pid); - sh->needs_parsing = 1; - sh->format = IS_AUDIO(es->type) ? es->type : es->subtype; - mp_set_audio_codec_from_tag(sh); - sh->ds = demuxer->audio; - - priv->ts.streams[es->pid].id = priv->last_aid; - priv->ts.streams[es->pid].sh = sh; - priv->ts.streams[es->pid].type = TYPE_AUDIO; - mp_msg(MSGT_DEMUX, MSGL_V, "\r\nADDED AUDIO PID %d, type: %x stream n. %d\r\n", es->pid, sh->format, priv->last_aid); - if (lang && lang[0]) - mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_AID_%d_LANG=%s\n", es->pid, lang); - priv->last_aid++; - - if(es->extradata && es->extradata_len) - { - sh->wf = malloc(sizeof(*sh->wf) + es->extradata_len); - sh->wf->cbSize = es->extradata_len; - memcpy(sh->wf + 1, es->extradata, es->extradata_len); - } - } - } - - if((IS_VIDEO(es->type) || IS_VIDEO(es->subtype)) && priv->last_vid+1 < MAX_V_STREAMS) - { - sh_video_t *sh = new_sh_video_vid(demuxer, priv->last_vid, es->pid); - if(sh) - { - sh->format = IS_VIDEO(es->type) ? es->type : es->subtype; - mp_set_video_codec_from_tag(sh); - sh->ds = demuxer->video; - - priv->ts.streams[es->pid].id = priv->last_vid; - priv->ts.streams[es->pid].sh = sh; - priv->ts.streams[es->pid].type = TYPE_VIDEO; - mp_msg(MSGT_DEMUX, MSGL_V, "\r\nADDED VIDEO PID %d, type: %x stream n. %d\r\n", es->pid, sh->format, priv->last_vid); - priv->last_vid++; - - - if(sh->format == VIDEO_AVC && es->extradata && es->extradata_len) - { - int w = 0, h = 0; - sh->bih = calloc(1, sizeof(*sh->bih) + es->extradata_len); - sh->bih->biSize= sizeof(*sh->bih) + es->extradata_len; - sh->bih->biCompression = sh->format; - memcpy(sh->bih + 1, es->extradata, es->extradata_len); - mp_msg(MSGT_DEMUXER,MSGL_DBG2, "EXTRADATA(%d BYTES): \n", es->extradata_len); - for(i = 0;i < es->extradata_len; i++) - mp_msg(MSGT_DEMUXER,MSGL_DBG2, "%02x ", (int) es->extradata[i]); - mp_msg(MSGT_DEMUXER,MSGL_DBG2,"\n"); - if(parse_avc_sps(es->extradata, es->extradata_len, &w, &h)) - { - sh->bih->biWidth = w; - sh->bih->biHeight = h; - } - } - } - } - - if(IS_SUB(es->type) && priv->last_sid+1 < MAX_S_STREAMS) - { - sh_sub_t *sh = new_sh_sub_sid_lang(demuxer, priv->last_sid, es->pid, pid_lang_from_pmt(priv, es->pid)); - if (sh) { - switch (es->type) { - case SPU_DVB: - sh->gsh->codec = "dvb_subtitle"; break; - case SPU_DVD: - sh->gsh->codec = "dvd_subtitle"; break; - case SPU_PGS: - sh->gsh->codec = "hdmv_pgs_subtitle"; break; - } - priv->ts.streams[es->pid].id = priv->last_sid; - priv->ts.streams[es->pid].sh = sh; - priv->ts.streams[es->pid].type = TYPE_SUB; - priv->last_sid++; - } - } -} - -static int ts_check_file(demuxer_t * demuxer) -{ - const int buf_size = (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS); - unsigned char buf[TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS], done = 0, *ptr; - uint32_t _read, i, count = 0, is_ts; - int cc[NB_PID_MAX], last_cc[NB_PID_MAX], pid, cc_ok, c, good, bad; - uint8_t size = 0; - int64_t pos = 0; - int64_t init_pos; - - mp_msg(MSGT_DEMUX, MSGL_V, "Checking for MPEG-TS...\n"); - - init_pos = stream_tell(demuxer->stream); - is_ts = 0; - while(! done) - { - i = 1; - c = 0; - - while(((c=stream_read_char(demuxer->stream)) != 0x47) - && (c >= 0) - && (i < MAX_CHECK_SIZE) - && ! demuxer->stream->eof - ) i++; - - - if(c != 0x47) - { - mp_msg(MSGT_DEMUX, MSGL_V, "THIS DOESN'T LOOK LIKE AN MPEG-TS FILE!\n"); - is_ts = 0; - done = 1; - continue; - } - - pos = stream_tell(demuxer->stream) - 1; - buf[0] = c; - _read = stream_read(demuxer->stream, &buf[1], buf_size-1); - - if(_read < buf_size-1) - { - mp_msg(MSGT_DEMUX, MSGL_V, "COULDN'T READ ENOUGH DATA, EXITING TS_CHECK\n"); - return 0; - } - - size = get_packet_size(buf, buf_size); - if(size) - { - done = 1; - is_ts = 1; - } - - if(pos - init_pos >= MAX_CHECK_SIZE) - { - done = 1; - is_ts = 0; - } - } - - mp_msg(MSGT_DEMUX, MSGL_V, "TRIED UP TO POSITION %"PRIu64", FOUND %x, packet_size= %d, SEEMS A TS? %d\n", (uint64_t) pos, c, size, is_ts); - stream_seek(demuxer->stream, pos); - - if(! is_ts) - return 0; - - //LET'S CHECK continuity counters - good = bad = 0; - for(count = 0; count < NB_PID_MAX; count++) - { - cc[count] = last_cc[count] = -1; - } - - for(count = 0; count < NUM_CONSECUTIVE_TS_PACKETS; count++) - { - ptr = &(buf[size * count]); - pid = ((ptr[1] & 0x1f) << 8) | ptr[2]; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "BUF: %02x %02x %02x %02x, PID %d, SIZE: %d \n", - ptr[0], ptr[1], ptr[2], ptr[3], pid, size); - - if((pid == 8191) || (pid < 16)) - continue; - - cc[pid] = (ptr[3] & 0xf); - cc_ok = (last_cc[pid] < 0) || ((((last_cc[pid] + 1) & 0x0f) == cc[pid])); - mp_msg(MSGT_DEMUX, MSGL_DBG2, "PID %d, COMPARE CC %d AND LAST_CC %d\n", pid, cc[pid], last_cc[pid]); - if(! cc_ok) - //return 0; - bad++; - else - good++; - - last_cc[pid] = cc[pid]; - } - - mp_msg(MSGT_DEMUX, MSGL_V, "GOOD CC: %d, BAD CC: %d\n", good, bad); - - if(good >= bad) - return size; - else - return 0; -} - - -static int32_t progid_idx_in_pmt(ts_priv_t *priv, uint16_t progid) -{ - int x; - - if(priv->pmt == NULL) - return -1; - - for(x = 0; x < priv->pmt_cnt; x++) - { - if(priv->pmt[x].progid == progid) - return x; - } - - return -1; -} - - -static int32_t progid_for_pid(ts_priv_t *priv, int pid, int32_t req) //finds the first program listing a pid -{ - int i, j; - pmt_t *pmt; - - - if(priv->pmt == NULL) - return -1; - - - for(i=0; i < priv->pmt_cnt; i++) - { - pmt = &(priv->pmt[i]); - - if(pmt->es == NULL) - return -1; - - for(j = 0; j < pmt->es_cnt; j++) - { - if(pmt->es[j].pid == pid) - { - if((req == 0) || (req == pmt->progid)) - return pmt->progid; - } - } - - } - return -1; -} - -static int32_t prog_pcr_pid(ts_priv_t *priv, int progid) -{ - int i; - - if(priv->pmt == NULL) - return -1; - for(i=0; i < priv->pmt_cnt; i++) - { - if(priv->pmt[i].progid == progid) - return priv->pmt[i].PCR_PID; - } - return -1; -} - - -static int pid_match_lang(ts_priv_t *priv, uint16_t pid, char *lang) -{ - uint16_t i, j; - pmt_t *pmt; - - if(priv->pmt == NULL) - return -1; - - for(i=0; i < priv->pmt_cnt; i++) - { - pmt = &(priv->pmt[i]); - - if(pmt->es == NULL) - return -1; - - for(j = 0; j < pmt->es_cnt; j++) - { - if(pmt->es[j].pid != pid) - continue; - - mp_msg(MSGT_DEMUXER, MSGL_V, "CMP LANG %s AND %s, pids: %d %d\n",pmt->es[j].lang, lang, pmt->es[j].pid, pid); - if(strncmp(pmt->es[j].lang, lang, 3) == 0) - { - return 1; - } - } - - } - - return -1; -} - -typedef struct { - int32_t atype, vtype, stype; //types - int32_t apid, vpid, spid; //stream ids - char alang[4]; //languages - uint16_t prog; - int64_t probe; -} tsdemux_init_t; - -//second stage: returns the count of A52 syncwords found -static int a52_check(char *buf, int len) -{ - int cnt, frame_length = 0, ok, srate; - - cnt = ok = 0; - if(len < 8) - return 0; - - while(cnt < len - 7) - { - if(buf[cnt] == 0x0B && buf[cnt+1] == 0x77) - { - frame_length = mp_a52_framesize(&buf[cnt], &srate); - if(frame_length>=7 && frame_length<=3840) - { - cnt += frame_length; - ok++; - } - else - cnt++; - } - else - cnt++; - } - - mp_msg(MSGT_DEMUXER, MSGL_V, "A52_CHECK(%d input bytes), found %d frame syncwords of %d bytes length\n", len, ok, frame_length); - return ok; -} - - -static int64_t ts_detect_streams(demuxer_t *demuxer, tsdemux_init_t *param) -{ - int video_found = 0, audio_found = 0, i, num_packets = 0, req_apid, req_vpid, req_spid; - int is_audio, is_video, is_sub, has_tables; - int32_t p, chosen_pid = 0; - int64_t pos=0, ret = 0, init_pos, end_pos; - ES_stream_t es; - unsigned char tmp[TS_FEC_PACKET_SIZE]; - ts_priv_t *priv = (ts_priv_t*) demuxer->priv; - struct { - char *buf; - int pos; - } pes_priv1[8192], *pptr; - char *tmpbuf; - - priv->last_pid = 8192; //invalid pid - - req_apid = param->apid; - req_vpid = param->vpid; - req_spid = param->spid; - - has_tables = 0; - memset(pes_priv1, 0, sizeof(pes_priv1)); - init_pos = stream_tell(demuxer->stream); - mp_msg(MSGT_DEMUXER, MSGL_V, "PROBING UP TO %"PRIu64", PROG: %d\n", (uint64_t) param->probe, param->prog); - end_pos = init_pos + (param->probe ? param->probe : TS_MAX_PROBE_SIZE); - while(1) - { - pos = stream_tell(demuxer->stream); - if(pos > end_pos || demuxer->stream->eof) - break; - - if(ts_parse(demuxer, &es, tmp, 1)) - { - //Non PES-aligned A52 audio may escape detection if PMT is not present; - //in this case we try to find at least 3 A52 syncwords - if((es.type == PES_PRIVATE1) && (! audio_found) && req_apid > -2) - { - pptr = &pes_priv1[es.pid]; - if(pptr->pos < 64*1024) - { - tmpbuf = realloc(pptr->buf, pptr->pos + es.size); - if(tmpbuf != NULL) - { - pptr->buf = tmpbuf; - memcpy(&(pptr->buf[ pptr->pos ]), es.start, es.size); - pptr->pos += es.size; - if(a52_check(pptr->buf, pptr->pos) > 2) - { - param->atype = AUDIO_A52; - param->apid = es.pid; - es.type = AUDIO_A52; - } - } - } - } - - is_audio = IS_AUDIO(es.type) || ((es.type==SL_PES_STREAM) && IS_AUDIO(es.subtype)); - is_video = IS_VIDEO(es.type) || ((es.type==SL_PES_STREAM) && IS_VIDEO(es.subtype)); - is_sub = IS_SUB(es.type); - - - if((! is_audio) && (! is_video) && (! is_sub)) - continue; - if(is_audio && req_apid==-2) - continue; - - if(is_video) - { - chosen_pid = (req_vpid == es.pid); - if((! chosen_pid) && (req_vpid > 0)) - continue; - } - else if(is_audio) - { - if(req_apid > 0) - { - chosen_pid = (req_apid == es.pid); - if(! chosen_pid) - continue; - } - else if(param->alang[0] > 0 && es.lang[0] > 0) - { - if(pid_match_lang(priv, es.pid, param->alang) == -1) - continue; - - chosen_pid = 1; - param->apid = req_apid = es.pid; - } - } - else if(is_sub) - { - chosen_pid = (req_spid == es.pid); - if((! chosen_pid) && (req_spid > 0)) - continue; - } - - if(req_apid < 0 && (param->alang[0] == 0) && req_vpid < 0 && req_spid < 0) - chosen_pid = 1; - - if((ret == 0) && chosen_pid) - { - ret = stream_tell(demuxer->stream); - } - - p = progid_for_pid(priv, es.pid, param->prog); - if(p != -1) - { - has_tables++; - if(!param->prog && chosen_pid) - param->prog = p; - } - - if((param->prog > 0) && (param->prog != p)) - { - if(audio_found) - { - if(is_video && (req_vpid == es.pid)) - { - param->vtype = IS_VIDEO(es.type) ? es.type : es.subtype; - param->vpid = es.pid; - video_found = 1; - break; - } - } - - if(video_found) - { - if(is_audio && (req_apid == es.pid)) - { - param->atype = IS_AUDIO(es.type) ? es.type : es.subtype; - param->apid = es.pid; - audio_found = 1; - break; - } - } - - - continue; - } - - - mp_msg(MSGT_DEMUXER, MSGL_DBG2, "TYPE: %x, PID: %d, PROG FOUND: %d\n", es.type, es.pid, param->prog); - - - if(is_video) - { - if((req_vpid == -1) || (req_vpid == es.pid)) - { - param->vtype = IS_VIDEO(es.type) ? es.type : es.subtype; - param->vpid = es.pid; - video_found = 1; - } - } - - - if(((req_vpid == -2) || (num_packets >= NUM_CONSECUTIVE_AUDIO_PACKETS)) && audio_found && !param->probe) - { - //novideo or we have at least 348 audio packets (64 KB) without video (TS with audio only) - param->vtype = 0; - break; - } - - if(is_sub) - { - if((req_spid == -1) || (req_spid == es.pid)) - { - param->stype = es.type; - param->spid = es.pid; - } - } - - if(is_audio) - { - if((req_apid == -1) || (req_apid == es.pid)) - { - param->atype = IS_AUDIO(es.type) ? es.type : es.subtype; - param->apid = es.pid; - audio_found = 1; - } - } - - if(audio_found && (param->apid == es.pid) && (! video_found)) - num_packets++; - - if((has_tables==0) && (video_found && audio_found) && (pos >= 1000000)) - break; - } - } - - for(i=0; i<8192; i++) - { - if(pes_priv1[i].buf != NULL) - { - free(pes_priv1[i].buf); - pes_priv1[i].buf = NULL; - pes_priv1[i].pos = 0; - } - } - - if(video_found) - { - if(param->vtype == VIDEO_MPEG1) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG1(pid=%d) ", param->vpid); - else if(param->vtype == VIDEO_MPEG2) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG2(pid=%d) ", param->vpid); - else if(param->vtype == VIDEO_MPEG4) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG4(pid=%d) ", param->vpid); - else if(param->vtype == VIDEO_H264) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO H264(pid=%d) ", param->vpid); - else if(param->vtype == VIDEO_VC1) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO VC1(pid=%d) ", param->vpid); - else if(param->vtype == VIDEO_AVC) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO AVC(NAL-H264, pid=%d) ", param->vpid); - } - else - { - param->vtype = UNKNOWN; - //WE DIDN'T MATCH ANY VIDEO STREAM - mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO VIDEO! "); - } - - if(param->atype == AUDIO_MP2) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO MPA(pid=%d)", param->apid); - else if(param->atype == AUDIO_A52) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO A52(pid=%d)", param->apid); - else if(param->atype == AUDIO_DTS) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO DTS(pid=%d)", param->apid); - else if(param->atype == AUDIO_LPCM_BE) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO LPCM(pid=%d)", param->apid); - else if(param->atype == AUDIO_PCM_BR) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO PCMBR(pid=%d)", param->apid); - else if(param->atype == AUDIO_AAC) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO AAC(pid=%d)", param->apid); - else if(param->atype == AUDIO_AAC_LATM) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO AAC LATM(pid=%d)", param->apid); - else if(param->atype == AUDIO_TRUEHD) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO TRUEHD(pid=%d)", param->apid); - else if(param->atype == AUDIO_S302M) - mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO S302M(pid=%d)", param->apid); - else - { - audio_found = 0; - param->atype = UNKNOWN; - //WE DIDN'T MATCH ANY AUDIO STREAM, SO WE FORCE THE DEMUXER TO IGNORE AUDIO - mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO AUDIO! (try increasing -tsprobe)"); - } - - if(IS_SUB(param->stype)) - mp_msg(MSGT_DEMUXER, MSGL_INFO, " SUB %s(pid=%d) ", (param->stype==SPU_DVD ? "DVD" : param->stype==SPU_DVB ? "DVB" : "Teletext"), param->spid); - else - { - param->stype = UNKNOWN; - mp_msg(MSGT_DEMUXER, MSGL_INFO, " NO SUBS (yet)! "); - } - - if(video_found || audio_found) - { - if(!param->prog) - { - p = progid_for_pid(priv, video_found ? param->vpid : param->apid, 0); - if(p != -1) - param->prog = p; - } - - if(demuxer->stream->eof && (ret == 0)) - ret = init_pos; - mp_msg(MSGT_DEMUXER, MSGL_INFO, " PROGRAM N. %d\n", param->prog); - } - else - mp_msg(MSGT_DEMUXER, MSGL_INFO, "\n"); - - - for(i=0; i<NB_PID_MAX; i++) - { - if(priv->ts.pids[i] != NULL) - { - priv->ts.pids[i]->payload_size = 0; - priv->ts.pids[i]->pts = priv->ts.pids[i]->last_pts = 0; - priv->ts.pids[i]->last_cc = -1; - priv->ts.pids[i]->is_synced = 0; - } - } - - return ret; -} - -static int parse_avc_sps(uint8_t *buf, int len, int *w, int *h) -{ - int sps, sps_len; - unsigned char *ptr; - mp_mpeg_header_t picture; - if(len < 6) - return 0; - sps = buf[5] & 0x1f; - if(!sps) - return 0; - sps_len = (buf[6] << 8) | buf[7]; - if(!sps_len || (sps_len > len - 8)) - return 0; - ptr = &(buf[8]); - picture.display_picture_width = picture.display_picture_height = 0; - h264_parse_sps(&picture, ptr, len - 8); - if(!picture.display_picture_width || !picture.display_picture_height) - return 0; - *w = picture.display_picture_width; - *h = picture.display_picture_height; - return 1; -} - -static demuxer_t *demux_open_ts(demuxer_t * demuxer) -{ - int i; - uint8_t packet_size; - sh_video_t *sh_video; - sh_audio_t *sh_audio; - int64_t start_pos; - tsdemux_init_t params; - ts_priv_t * priv = demuxer->priv; - - mp_msg(MSGT_DEMUX, MSGL_V, "DEMUX OPEN, AUDIO_ID: %d, VIDEO_ID: %d, SUBTITLE_ID: %d,\n", - demuxer->audio->id, demuxer->video->id, demuxer->sub->id); - - - demuxer->type= DEMUXER_TYPE_MPEG_TS; - demuxer->ts_resets_possible = true; - - packet_size = ts_check_file(demuxer); - if(!packet_size) - return NULL; - - priv = calloc(1, sizeof(ts_priv_t)); - if(priv == NULL) - { - mp_msg(MSGT_DEMUX, MSGL_FATAL, "DEMUX_OPEN_TS, couldn't allocate enough memory for ts->priv, exit\n"); - return NULL; - } - - for(i=0; i < NB_PID_MAX; i++) - { - priv->ts.pids[i] = NULL; - priv->ts.streams[i].id = -3; - } - priv->pat.progs = NULL; - priv->pat.progs_cnt = 0; - priv->pat.section.buffer = NULL; - priv->pat.section.buffer_len = 0; - - priv->pmt = NULL; - priv->pmt_cnt = 0; - - priv->keep_broken = ts_keep_broken; - priv->ts.packet_size = packet_size; - - - demuxer->priv = priv; - - params.atype = params.vtype = params.stype = UNKNOWN; - params.apid = demuxer->audio->id; - params.vpid = demuxer->video->id; - params.spid = demuxer->sub->id; - params.prog = ts_prog; - params.probe = ts_probe; - - if(demuxer->opts->audio_lang != NULL) - { - strncpy(params.alang, demuxer->opts->audio_lang[0], 3); - params.alang[3] = 0; - } - else - memset(params.alang, 0, 4); - - start_pos = ts_detect_streams(demuxer, ¶ms); - - demuxer->sub->id = params.spid; - priv->prog = params.prog; - - if(params.vtype != UNKNOWN) - { - ts_add_stream(demuxer, priv->ts.pids[params.vpid]); - sh_video = priv->ts.streams[params.vpid].sh; - demuxer->video->id = priv->ts.streams[params.vpid].id; - sh_video->ds = demuxer->video; - sh_video->format = params.vtype; - mp_set_video_codec_from_tag(sh_video); - demuxer->video->sh = sh_video; - } - - if(params.atype != UNKNOWN) - { - ES_stream_t *es = priv->ts.pids[params.apid]; - - if(!IS_AUDIO(es->type) && !IS_AUDIO(es->subtype) && IS_AUDIO(params.atype)) es->subtype = params.atype; - ts_add_stream(demuxer, priv->ts.pids[params.apid]); - sh_audio = priv->ts.streams[params.apid].sh; - demuxer->audio->id = priv->ts.streams[params.apid].id; - sh_audio->ds = demuxer->audio; - sh_audio->format = params.atype; - mp_set_audio_codec_from_tag(sh_audio); - demuxer->audio->sh = sh_audio; - } - - - mp_msg(MSGT_DEMUXER,MSGL_V, "Opened TS demuxer, audio: %x(pid %d), video: %x(pid %d)...POS=%"PRIu64", PROBE=%"PRIu64"\n", params.atype, demuxer->audio->id, params.vtype, demuxer->video->id, (uint64_t) start_pos, ts_probe); - - - start_pos = start_pos <= priv->ts.packet_size ? - demuxer->stream->start_pos : - start_pos - priv->ts.packet_size; - demuxer->movi_start = start_pos; - demuxer->reference_clock = MP_NOPTS_VALUE; - stream_seek(demuxer->stream, start_pos); //IF IT'S FROM A PIPE IT WILL FAIL, BUT WHO CARES? - - - priv->last_pid = 8192; //invalid pid - - for(i = 0; i < 3; i++) - { - priv->fifo[i].pack = NULL; - priv->fifo[i].offset = 0; - } - priv->fifo[0].ds = demuxer->audio; - priv->fifo[1].ds = demuxer->video; - priv->fifo[2].ds = demuxer->sub; - - priv->fifo[0].buffer_size = 1536; - priv->fifo[1].buffer_size = 32767; - priv->fifo[2].buffer_size = 32767; - - priv->pat.section.buffer_len = 0; - for(i = 0; i < priv->pmt_cnt; i++) - priv->pmt[i].section.buffer_len = 0; - - demuxer->filepos = stream_tell(demuxer->stream); - return demuxer; -} - -static void demux_close_ts(demuxer_t * demuxer) -{ - uint16_t i; - ts_priv_t *priv = (ts_priv_t*) demuxer->priv; - - if(priv) - { - free(priv->pat.section.buffer); - free(priv->pat.progs); - - if(priv->pmt) - { - for(i = 0; i < priv->pmt_cnt; i++) - { - free(priv->pmt[i].section.buffer); - free(priv->pmt[i].es); - } - free(priv->pmt); - } - for (i = 0; i < NB_PID_MAX; i++) - { - free(priv->ts.pids[i]); - priv->ts.pids[i] = NULL; - } - for (i = 0; i < 3; i++) - { - if (priv->fifo[i].pack) - free_demux_packet(priv->fifo[i].pack); - priv->fifo[i].pack = NULL; - } - free(priv); - } - demuxer->priv=NULL; -} - - -#define getbits mp_getbits - -static int mp4_parse_sl_packet(pmt_t *pmt, uint8_t *buf, uint16_t packet_len, int pid, ES_stream_t *pes_es) -{ - int i, n, m, mp4_es_id = -1; - uint64_t v = 0; - uint32_t pl_size = 0; - int deg_flag = 0; - mp4_es_descr_t *es = NULL; - mp4_sl_config_t *sl = NULL; - uint8_t au_start = 0, au_end = 0, rap_flag = 0, ocr_flag = 0, padding = 0, padding_bits = 0, idle = 0; - - pes_es->is_synced = 0; - mp_msg(MSGT_DEMUXER,MSGL_V, "mp4_parse_sl_packet, pid: %d, pmt: %pm, packet_len: %d\n", pid, pmt, packet_len); - if(! pmt || !packet_len) - return 0; - - for(i = 0; i < pmt->es_cnt; i++) - { - if(pmt->es[i].pid == pid) - mp4_es_id = pmt->es[i].mp4_es_id; - } - if(mp4_es_id < 0) - return -1; - - for(i = 0; i < pmt->mp4es_cnt; i++) - { - if(pmt->mp4es[i].id == mp4_es_id) - es = &(pmt->mp4es[i]); - } - if(! es) - return -1; - - pes_es->subtype = es->decoder.object_type; - - sl = &(es->sl); - if(!sl) - return -1; - - //now es is the complete es_descriptor of out mp4 ES stream - mp_msg(MSGT_DEMUXER,MSGL_DBG2, "ID: %d, FLAGS: 0x%x, subtype: %x\n", es->id, sl->flags, pes_es->subtype); - - n = 0; - if(sl->au_start) - pes_es->sl.au_start = au_start = getbits(buf, n++, 1); - else - pes_es->sl.au_start = (pes_es->sl.last_au_end ? 1 : 0); - if(sl->au_end) - pes_es->sl.au_end = au_end = getbits(buf, n++, 1); - - if(!sl->au_start && !sl->au_end) - { - pes_es->sl.au_start = pes_es->sl.au_end = au_start = au_end = 1; - } - pes_es->sl.last_au_end = pes_es->sl.au_end; - - - if(sl->ocr_len > 0) - ocr_flag = getbits(buf, n++, 1); - if(sl->idle) - idle = getbits(buf, n++, 1); - if(sl->padding) - padding = getbits(buf, n++, 1); - if(padding) - { - padding_bits = getbits(buf, n, 3); - n += 3; - } - - if(idle || (padding && !padding_bits)) - { - pes_es->payload_size = 0; - return -1; - } - - //(! idle && (!padding || padding_bits != 0)) is true - n += sl->packet_seqnum_len; - if(sl->degr_len) - deg_flag = getbits(buf, n++, 1); - if(deg_flag) - n += sl->degr_len; - - if(ocr_flag) - { - n += sl->ocr_len; - mp_msg(MSGT_DEMUXER,MSGL_DBG2, "OCR: %d bits\n", sl->ocr_len); - } - - if(packet_len * 8 <= n) - return -1; - - mp_msg(MSGT_DEMUXER,MSGL_DBG2, "\nAU_START: %d, AU_END: %d\n", au_start, au_end); - if(au_start) - { - int dts_flag = 0, cts_flag = 0, ib_flag = 0; - - if(sl->random_accesspoint) - rap_flag = getbits(buf, n++, 1); - - //check commented because it seems it's rarely used, and we need this flag set in case of au_start - //the decoder will eventually discard the payload if it can't decode it - //if(rap_flag || sl->random_accesspoint_only) - pes_es->is_synced = 1; - - n += sl->au_seqnum_len; - if(packet_len * 8 <= n+8) - return -1; - if(sl->use_ts) - { - dts_flag = getbits(buf, n++, 1); - cts_flag = getbits(buf, n++, 1); - } - if(sl->instant_bitrate_len) - ib_flag = getbits(buf, n++, 1); - if(packet_len * 8 <= n+8) - return -1; - if(dts_flag && (sl->ts_len > 0)) - { - n += sl->ts_len; - mp_msg(MSGT_DEMUXER,MSGL_DBG2, "DTS: %d bits\n", sl->ts_len); - } - if(packet_len * 8 <= n+8) - return -1; - if(cts_flag && (sl->ts_len > 0)) - { - int i = 0, m; - - while(i < sl->ts_len) - { - m = FFMIN(8, sl->ts_len - i); - v |= getbits(buf, n, m); - if(sl->ts_len - i > 8) - v <<= 8; - i += m; - n += m; - if(packet_len * 8 <= n+8) - return -1; - } - - pes_es->pts = (double) v / (double) sl->ts_resolution; - mp_msg(MSGT_DEMUXER,MSGL_DBG2, "CTS: %d bits, value: %"PRIu64"/%d = %.3f\n", sl->ts_len, v, sl->ts_resolution, pes_es->pts); - } - - - i = 0; - pl_size = 0; - while(i < sl->au_len) - { - m = FFMIN(8, sl->au_len - i); - pl_size |= getbits(buf, n, m); - if(sl->au_len - i > 8) - pl_size <<= 8; - i += m; - n += m; - if(packet_len * 8 <= n+8) - return -1; - } - mp_msg(MSGT_DEMUXER,MSGL_DBG2, "AU_LEN: %u (%d bits)\n", pl_size, sl->au_len); - if(ib_flag) - n += sl->instant_bitrate_len; - } - - m = (n+7)/8; - if(0 < pl_size && pl_size < pes_es->payload_size) - pes_es->payload_size = pl_size; - - mp_msg(MSGT_DEMUXER,MSGL_V, "mp4_parse_sl_packet, n=%d, m=%d, size from pes hdr: %u, sl hdr size: %u, RAP FLAGS: %d/%d\n", - n, m, pes_es->payload_size, pl_size, (int) rap_flag, (int) sl->random_accesspoint_only); - - return m; -} - -//this function parses the extension fields in the PES header and returns the substream_id, or -1 in case of errors -static int parse_pes_extension_fields(unsigned char *p, int pkt_len) -{ - int skip; - unsigned char flags; - - if(!(p[7] & 0x1)) //no extension_field - return -1; - skip = 9; - if(p[7] & 0x80) - { - skip += 5; - if(p[7] & 0x40) - skip += 5; - } - if(p[7] & 0x20) //escr_flag - skip += 6; - if(p[7] & 0x10) //es_rate_flag - skip += 3; - if(p[7] & 0x08)//dsm_trick_mode is unsupported, skip - { - skip = 0;//don't let's parse the extension fields - } - if(p[7] & 0x04) //additional_copy_info - skip += 1; - if(p[7] & 0x02) //pes_crc_flag - skip += 2; - if(skip >= pkt_len) //too few bytes - return -1; - flags = p[skip]; - skip++; - if(flags & 0x80) //pes_private_data_flag - skip += 16; - if(skip >= pkt_len) - return -1; - if(flags & 0x40) //pack_header_field_flag - { - unsigned char l = p[skip]; - skip += l; - } - if(flags & 0x20) //program_packet_sequence_counter - skip += 2; - if(flags & 0x10) //p_std - skip += 2; - if(skip >= pkt_len) - return -1; - if(flags & 0x01) //finally the long desired pes_extension2 - { - unsigned char l = p[skip]; //ext2 flag+len - skip++; - if((l == 0x81) && (skip < pkt_len)) - { - int ssid = p[skip]; - mp_msg(MSGT_IDENTIFY, MSGL_V, "SUBSTREAM_ID=%d (0x%02X)\n", ssid, ssid); - return ssid; - } - } - - return -1; -} - -static int pes_parse2(unsigned char *buf, uint16_t packet_len, ES_stream_t *es, int32_t type_from_pmt, pmt_t *pmt, int pid) -{ - unsigned char *p; - uint32_t header_len; - int64_t pts; - uint32_t stream_id; - uint32_t pkt_len, pes_is_aligned; - - //Here we are always at the start of a PES packet - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2(%p, %d): \n", buf, (uint32_t) packet_len); - - if(packet_len == 0 || packet_len > 184) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2, BUFFER LEN IS TOO SMALL OR TOO BIG: %d EXIT\n", packet_len); - return 0; - } - - p = buf; - pkt_len = packet_len; - - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: HEADER %02x %02x %02x %02x\n", p[0], p[1], p[2], p[3]); - if (p[0] || p[1] || (p[2] != 1)) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: error HEADER %02x %02x %02x (should be 0x000001) \n", p[0], p[1], p[2]); - return 0 ; - } - - packet_len -= 6; - if(packet_len==0) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: packet too short: %d, exit\n", packet_len); - return 0; - } - - es->payload_size = (p[4] << 8 | p[5]); - pes_is_aligned = (p[6] & 4); - - stream_id = p[3]; - - - if (p[7] & 0x80) - { /* pts available */ - pts = (int64_t)(p[9] & 0x0E) << 29 ; - pts |= p[10] << 22 ; - pts |= (p[11] & 0xFE) << 14 ; - pts |= p[12] << 7 ; - pts |= (p[13] & 0xFE) >> 1 ; - - es->pts = pts / 90000.0; - } - else - es->pts = 0.0; - - - header_len = p[8]; - - - if (header_len + 9 > pkt_len) //9 are the bytes read up to the header_length field - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "demux_ts: illegal value for PES_header_data_length (0x%02x)\n", header_len); - return 0; - } - - if(stream_id==0xfd) - { - int ssid = parse_pes_extension_fields(p, pkt_len); - if((audio_substream_id!=-1) && (ssid != audio_substream_id)) - return 0; - if(ssid == 0x72 && type_from_pmt != AUDIO_DTS && type_from_pmt != SPU_PGS) - es->type = type_from_pmt = AUDIO_TRUEHD; - } - - p += header_len + 9; - packet_len -= header_len + 3; - - if(es->payload_size) - es->payload_size -= header_len + 3; - - - es->is_synced = 1; //only for SL streams we have to make sure it's really true, see below - if (stream_id == 0xbd) - { - mp_msg(MSGT_DEMUX, MSGL_DBG3, "pes_parse2: audio buf = %02X %02X %02X %02X %02X %02X %02X %02X, 80: %d\n", - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[0] & 0x80); - - - /* - * we check the descriptor tag first because some stations - * do not include any of the A52 header info in their audio tracks - * these "raw" streams may begin with a byte that looks like a stream type. - */ - - - if(type_from_pmt == SPU_PGS) - { - es->start = p; - es->size = packet_len; - es->type = SPU_PGS; - es->payload_size -= packet_len; - return 1; - } - if( - (type_from_pmt == AUDIO_A52) || /* A52 - raw */ - (packet_len >= 2 && p[0] == 0x0B && p[1] == 0x77) /* A52 - syncword */ - ) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "A52 RAW OR SYNCWORD\n"); - es->start = p; - es->size = packet_len; - es->type = AUDIO_A52; - es->payload_size -= packet_len; - - return 1; - } - /* SPU SUBS */ - else if(type_from_pmt == SPU_DVB || - (packet_len >= 2 && (p[0] == 0x20) && pes_is_aligned)) // && p[1] == 0x00)) - { - // offset/length fiddling to make decoding with lavc possible - es->start = p + 2; - es->size = packet_len - 2; - es->type = SPU_DVB; - es->payload_size -= packet_len; - - return 1; - } - else if (pes_is_aligned && packet_len >= 1 && ((p[0] & 0xE0) == 0x20)) //SPU_DVD - { - //DVD SUBS - es->start = p+1; - es->size = packet_len-1; - es->type = SPU_DVD; - es->payload_size -= packet_len; - - return 1; - } - else if (pes_is_aligned && packet_len >= 4 && (p[0] & 0xF8) == 0x80) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "A52 WITH HEADER\n"); - es->start = p+4; - es->size = packet_len - 4; - es->type = AUDIO_A52; - es->payload_size -= packet_len; - - return 1; - } - else if (pes_is_aligned && packet_len >= 1 && ((p[0]&0xf0) == 0xa0)) - { - int pcm_offset; - - for (pcm_offset=0; ++pcm_offset < packet_len-1 ; ) - { - if (p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80) - { /* START */ - pcm_offset += 2; - break; - } - } - - es->start = p + pcm_offset; - es->size = packet_len - pcm_offset; - es->type = AUDIO_LPCM_BE; - es->payload_size -= packet_len; - - return 1; - } - else - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "PES_PRIVATE1\n"); - es->start = p; - es->size = packet_len; - es->type = (type_from_pmt == UNKNOWN ? PES_PRIVATE1 : type_from_pmt); - es->payload_size -= packet_len; - - return 1; - } - } - else if((stream_id >= 0xe0 && stream_id <= 0xef) || (stream_id == 0xfd && type_from_pmt != UNKNOWN)) - { - es->start = p; - es->size = packet_len; - if(type_from_pmt != UNKNOWN) - es->type = type_from_pmt; - else - es->type = VIDEO_MPEG2; - if(es->payload_size) - es->payload_size -= packet_len; - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: M2V size %d\n", es->size); - return 1; - } - else if (stream_id == 0xfa) - { - int l; - - es->is_synced = 0; - if(type_from_pmt != UNKNOWN) //MP4 A/V or SL - { - es->start = p; - es->size = packet_len; - es->type = type_from_pmt; - - if(type_from_pmt == SL_PES_STREAM) - { - //if(pes_is_aligned) - //{ - l = mp4_parse_sl_packet(pmt, p, packet_len, pid, es); - mp_msg(MSGT_DEMUX, MSGL_DBG2, "L=%d, TYPE=%x\n", l, type_from_pmt); - if(l < 0) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: couldn't parse SL header, passing along full PES payload\n"); - l = 0; - } - //} - - es->start += l; - es->size -= l; - } - - if(es->payload_size) - es->payload_size -= packet_len; - return 1; - } - } - else if ((stream_id & 0xe0) == 0xc0) - { - es->start = p; - es->size = packet_len; - - if(type_from_pmt != UNKNOWN) - es->type = type_from_pmt; - else - es->type = AUDIO_MP2; - - es->payload_size -= packet_len; - - return 1; - } - else if (type_from_pmt != -1) //as a last resort here we trust the PMT, if present - { - es->start = p; - es->size = packet_len; - es->type = type_from_pmt; - es->payload_size -= packet_len; - - return 1; - } - else - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: unknown packet, id: %x\n", stream_id); - } - - es->is_synced = 0; - return 0; -} - - - - -static int ts_sync(stream_t *stream) -{ - mp_msg(MSGT_DEMUX, MSGL_DBG3, "TS_SYNC \n"); - - while (!stream->eof) - if (stream_read_char(stream) == 0x47) - return 1; - - return 0; -} - - -static void ts_dump_streams(ts_priv_t *priv) -{ - int i; - - for(i = 0; i < 3; i++) - { - if((priv->fifo[i].pack != NULL) && (priv->fifo[i].offset != 0)) - { - resize_demux_packet(priv->fifo[i].pack, priv->fifo[i].offset); - ds_add_packet(priv->fifo[i].ds, priv->fifo[i].pack); - priv->fifo[i].offset = 0; - priv->fifo[i].pack = NULL; - } - } -} - - -static int32_t prog_idx_in_pat(ts_priv_t *priv, uint16_t progid) -{ - int x; - - if(priv->pat.progs == NULL) - return -1; - - for(x = 0; x < priv->pat.progs_cnt; x++) - { - if(priv->pat.progs[x].id == progid) - return x; - } - - return -1; -} - - -static int32_t prog_id_in_pat(ts_priv_t *priv, uint16_t pid) -{ - int x; - - if(priv->pat.progs == NULL) - return -1; - - for(x = 0; x < priv->pat.progs_cnt; x++) - { - if(priv->pat.progs[x].pmt_pid == pid) - return priv->pat.progs[x].id; - } - - return -1; -} - -static int collect_section(ts_section_t *section, int is_start, unsigned char *buff, int size) -{ - uint8_t *ptr; - uint16_t tlen; - int skip, tid; - - mp_msg(MSGT_DEMUX, MSGL_V, "COLLECT_SECTION, start: %d, size: %d, collected: %d\n", is_start, size, section->buffer_len); - if(! is_start && !section->buffer_len) - return 0; - - if(is_start) - { - if(! section->buffer) - { - section->buffer = malloc(4096 + 256); - if(section->buffer == NULL) - return 0; - } - section->buffer_len = 0; - } - - if(size + section->buffer_len > 4096+256) - { - mp_msg(MSGT_DEMUX, MSGL_V, "COLLECT_SECTION, excessive len: %d + %d\n", section->buffer_len, size); - return 0; - } - - memcpy(&(section->buffer[section->buffer_len]), buff, size); - section->buffer_len += size; - - if(section->buffer_len < 3) - return 0; - - skip = section->buffer[0]; - if(skip + 4 > section->buffer_len) - return 0; - - ptr = &(section->buffer[skip + 1]); - tid = ptr[0]; - tlen = ((ptr[1] & 0x0f) << 8) | ptr[2]; - mp_msg(MSGT_DEMUX, MSGL_V, "SKIP: %d+1, TID: %d, TLEN: %d, COLLECTED: %d\n", skip, tid, tlen, section->buffer_len); - if(section->buffer_len < (skip+1+3+tlen)) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "DATA IS NOT ENOUGH, NEXT TIME\n"); - return 0; - } - - return skip+1; -} - -static int parse_pat(ts_priv_t * priv, int is_start, unsigned char *buff, int size) -{ - int skip; - unsigned char *ptr; - unsigned char *base; - int entries, i; - uint16_t progid; - ts_section_t *section; - - section = &(priv->pat.section); - skip = collect_section(section, is_start, buff, size); - if(! skip) - return 0; - - ptr = &(section->buffer[skip]); - //PARSING - priv->pat.table_id = ptr[0]; - if(priv->pat.table_id != 0) - return 0; - priv->pat.ssi = (ptr[1] >> 7) & 0x1; - priv->pat.curr_next = ptr[5] & 0x01; - priv->pat.ts_id = (ptr[3] << 8 ) | ptr[4]; - priv->pat.version_number = (ptr[5] >> 1) & 0x1F; - priv->pat.section_length = ((ptr[1] & 0x03) << 8 ) | ptr[2]; - priv->pat.section_number = ptr[6]; - priv->pat.last_section_number = ptr[7]; - - //check_crc32(0xFFFFFFFFL, ptr, priv->pat.buffer_len - 4, &ptr[priv->pat.buffer_len - 4]); - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_PAT: section_len: %d, section %d/%d\n", priv->pat.section_length, priv->pat.section_number, priv->pat.last_section_number); - - entries = (int) (priv->pat.section_length - 9) / 4; //entries per section - - for(i=0; i < entries; i++) - { - int32_t idx; - base = &ptr[8 + i*4]; - progid = (base[0] << 8) | base[1]; - - if((idx = prog_idx_in_pat(priv, progid)) == -1) - { - priv->pat.progs = realloc_struct(priv->pat.progs, priv->pat.progs_cnt+1, sizeof(struct pat_progs_t)); - if(!priv->pat.progs) - { - int sz = sizeof(struct pat_progs_t) * (priv->pat.progs_cnt+1); - priv->pat.progs_cnt = 0; - mp_msg(MSGT_DEMUX, MSGL_ERR, "PARSE_PAT: COULDN'T REALLOC %d bytes, NEXT\n", sz); - break; - } - idx = priv->pat.progs_cnt; - priv->pat.progs_cnt++; - } - - priv->pat.progs[idx].id = progid; - priv->pat.progs[idx].pmt_pid = ((base[2] & 0x1F) << 8) | base[3]; - mp_msg(MSGT_DEMUX, MSGL_V, "PROG: %d (%d-th of %d), PMT: %d\n", priv->pat.progs[idx].id, i+1, entries, priv->pat.progs[idx].pmt_pid); - mp_msg(MSGT_IDENTIFY, MSGL_V, "PROGRAM_ID=%d (0x%02X), PMT_PID: %d(0x%02X)\n", - progid, progid, priv->pat.progs[idx].pmt_pid, priv->pat.progs[idx].pmt_pid); - } - - return 1; -} - - -static int32_t es_pid_in_pmt(pmt_t * pmt, uint16_t pid) -{ - uint16_t i; - - if(pmt == NULL) - return -1; - - if(pmt->es == NULL) - return -1; - - for(i = 0; i < pmt->es_cnt; i++) - { - if(pmt->es[i].pid == pid) - return (int32_t) i; - } - - return -1; -} - - -static uint16_t get_mp4_desc_len(uint8_t *buf, int *len) -{ - //uint16_t i = 0, size = 0; - int i = 0, j, size = 0; - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "PARSE_MP4_DESC_LEN(%d), bytes: ", *len); - j = FFMIN(*len, 4); - while(i < j) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, " %x ", buf[i]); - size |= (buf[i] & 0x7f); - if(!(buf[i] & 0x80)) - break; - size <<= 7; - i++; - } - mp_msg(MSGT_DEMUX, MSGL_DBG2, ", SIZE=%d\n", size); - - *len = i+1; - return size; -} - - -static uint16_t parse_mp4_slconfig_descriptor(uint8_t *buf, int len, void *elem) -{ - int i = 0; - mp4_es_descr_t *es; - mp4_sl_config_t *sl; - - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_MP4_SLCONFIG_DESCRIPTOR(%d)\n", len); - es = (mp4_es_descr_t *) elem; - if(!es) - { - mp_msg(MSGT_DEMUX, MSGL_V, "argh! NULL elem passed, skip\n"); - return len; - } - sl = &(es->sl); - - sl->ts_len = sl->ocr_len = sl->au_len = sl->instant_bitrate_len = sl->degr_len = sl->au_seqnum_len = sl->packet_seqnum_len = 0; - sl->ocr = sl->dts = sl->cts = 0; - - if(buf[0] == 0) - { - i++; - sl->flags = buf[i]; - i++; - sl->ts_resolution = (buf[i] << 24) | (buf[i+1] << 16) | (buf[i+2] << 8) | buf[i+3]; - i += 4; - sl->ocr_resolution = (buf[i] << 24) | (buf[i+1] << 16) | (buf[i+2] << 8) | buf[i+3]; - i += 4; - sl->ts_len = buf[i]; - i++; - sl->ocr_len = buf[i]; - i++; - sl->au_len = buf[i]; - i++; - sl->instant_bitrate_len = buf[i]; - i++; - sl->degr_len = (buf[i] >> 4) & 0x0f; - sl->au_seqnum_len = ((buf[i] & 0x0f) << 1) | ((buf[i+1] >> 7) & 0x01); - i++; - sl->packet_seqnum_len = ((buf[i] >> 2) & 0x1f); - i++; - - } - else if(buf[0] == 1) - { - sl->flags = 0; - sl->ts_resolution = 1000; - sl->ts_len = 32; - i++; - } - else if(buf[0] == 2) - { - sl->flags = 4; - i++; - } - else - { - sl->flags = 0; - i++; - } - - sl->au_start = (sl->flags >> 7) & 0x1; - sl->au_end = (sl->flags >> 6) & 0x1; - sl->random_accesspoint = (sl->flags >> 5) & 0x1; - sl->random_accesspoint_only = (sl->flags >> 4) & 0x1; - sl->padding = (sl->flags >> 3) & 0x1; - sl->use_ts = (sl->flags >> 2) & 0x1; - sl->idle = (sl->flags >> 1) & 0x1; - sl->duration = sl->flags & 0x1; - - if(sl->duration) - { - sl->timescale = (buf[i] << 24) | (buf[i+1] << 16) | (buf[i+2] << 8) | buf[i+3]; - i += 4; - sl->au_duration = (buf[i] << 8) | buf[i+1]; - i += 2; - sl->cts_duration = (buf[i] << 8) | buf[i+1]; - i += 2; - } - else //no support for fixed durations atm - sl->timescale = sl->au_duration = sl->cts_duration = 0; - - mp_msg(MSGT_DEMUX, MSGL_V, "MP4SLCONFIG(len=0x%x), predef: %d, flags: %x, use_ts: %d, tslen: %d, timescale: %d, dts: %"PRIu64", cts: %"PRIu64"\n", - len, buf[0], sl->flags, sl->use_ts, sl->ts_len, sl->timescale, (uint64_t) sl->dts, (uint64_t) sl->cts); - - return len; -} - -static int parse_mp4_descriptors(pmt_t *pmt, uint8_t *buf, int len, void *elem); - -static uint16_t parse_mp4_decoder_config_descriptor(pmt_t *pmt, uint8_t *buf, int len, void *elem) -{ - int i = 0, j; - mp4_es_descr_t *es; - mp4_decoder_config_t *dec; - - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_MP4_DECODER_CONFIG_DESCRIPTOR(%d)\n", len); - es = (mp4_es_descr_t *) elem; - if(!es) - { - mp_msg(MSGT_DEMUX, MSGL_V, "argh! NULL elem passed, skip\n"); - return len; - } - dec = (mp4_decoder_config_t*) &(es->decoder); - - dec->object_type = buf[i]; - dec->stream_type = (buf[i+1]>>2) & 0x3f; - - if(dec->object_type == 1 && dec->stream_type == 1) - { - dec->object_type = MP4_OD; - dec->stream_type = MP4_OD; - } - else if(dec->stream_type == 4) - { - if(dec->object_type == 0x6a) - dec->object_type = VIDEO_MPEG1; - if(dec->object_type >= 0x60 && dec->object_type <= 0x65) - dec->object_type = VIDEO_MPEG2; - else if(dec->object_type == 0x20) - dec->object_type = VIDEO_MPEG4; - else if(dec->object_type == 0x21) - dec->object_type = VIDEO_AVC; - /*else if(dec->object_type == 0x22) - fprintf(stderr, "TYPE 0x22\n");*/ - else dec->object_type = UNKNOWN; - } - else if(dec->stream_type == 5) - { - if(dec->object_type == 0x40) - dec->object_type = AUDIO_AAC; - else if(dec->object_type == 0x6b) - dec->object_type = AUDIO_MP2; - else if(dec->object_type >= 0x66 && dec->object_type <= 0x69) - dec->object_type = AUDIO_MP2; - else - dec->object_type = UNKNOWN; - } - else - dec->object_type = dec->stream_type = UNKNOWN; - - if(dec->object_type != UNKNOWN) - { - //update the type of the current stream - for(j = 0; j < pmt->es_cnt; j++) - { - if(pmt->es[j].mp4_es_id == es->id) - { - pmt->es[j].type = SL_PES_STREAM; - } - } - } - - if(len > 13) - parse_mp4_descriptors(pmt, &buf[13], len-13, dec); - - mp_msg(MSGT_DEMUX, MSGL_V, "MP4DECODER(0x%x), object_type: 0x%x, stream_type: 0x%x\n", len, dec->object_type, dec->stream_type); - - return len; -} - -static uint16_t parse_mp4_decoder_specific_descriptor(uint8_t *buf, int len, void *elem) -{ - int i; - mp4_decoder_config_t *dec; - - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_MP4_DECODER_SPECIFIC_DESCRIPTOR(%d)\n", len); - dec = (mp4_decoder_config_t *) elem; - if(!dec) - { - mp_msg(MSGT_DEMUX, MSGL_V, "argh! NULL elem passed, skip\n"); - return len; - } - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "MP4 SPECIFIC INFO BYTES: \n"); - for(i=0; i<len; i++) - mp_msg(MSGT_DEMUX, MSGL_DBG2, "%02x ", buf[i]); - mp_msg(MSGT_DEMUX, MSGL_DBG2, "\n"); - - if(len > MAX_EXTRADATA_SIZE) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "DEMUX_TS, EXTRADATA SUSPICIOUSLY BIG: %d, REFUSED\r\n", len); - return len; - } - memcpy(dec->buf, buf, len); - dec->buf_size = len; - - return len; -} - -static uint16_t parse_mp4_es_descriptor(pmt_t *pmt, uint8_t *buf, int len) -{ - int i = 0, j = 0, k, found; - uint8_t flag; - mp4_es_descr_t es, *target_es = NULL; - - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_MP4ES: len=%d\n", len); - memset(&es, 0, sizeof(mp4_es_descr_t)); - while(i < len) - { - es.id = (buf[i] << 8) | buf[i+1]; - mp_msg(MSGT_DEMUX, MSGL_V, "MP4ES_ID: %d\n", es.id); - i += 2; - flag = buf[i]; - i++; - if(flag & 0x80) - i += 2; - if(flag & 0x40) - i += buf[i]+1; - if(flag & 0x20) //OCR, maybe we need it - i += 2; - - j = parse_mp4_descriptors(pmt, &buf[i], len-i, &es); - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_MP4ES, types after parse_mp4_descriptors: 0x%x, 0x%x\n", es.decoder.object_type, es.decoder.stream_type); - if(es.decoder.object_type != UNKNOWN && es.decoder.stream_type != UNKNOWN) - { - found = 0; - //search this ES_ID if we already have it - for(k=0; k < pmt->mp4es_cnt; k++) - { - if(pmt->mp4es[k].id == es.id) - { - target_es = &(pmt->mp4es[k]); - found = 1; - } - } - - if(! found) - { - pmt->mp4es = realloc_struct(pmt->mp4es, pmt->mp4es_cnt+1, sizeof(mp4_es_descr_t)); - if(!pmt->mp4es) - { - pmt->mp4es_cnt = 0; - fprintf(stderr, "CAN'T REALLOC MP4_ES_DESCR\n"); - continue; - } - target_es = &(pmt->mp4es[pmt->mp4es_cnt]); - pmt->mp4es_cnt++; - } - memcpy(target_es, &es, sizeof(mp4_es_descr_t)); - mp_msg(MSGT_DEMUX, MSGL_V, "MP4ES_CNT: %d, ID=%d\n", pmt->mp4es_cnt, target_es->id); - } - - i += j; - } - - return len; -} - -static void parse_mp4_object_descriptor(pmt_t *pmt, uint8_t *buf, int len, void *elem) -{ - int i, j = 0, id; - - i=0; - id = (buf[0] << 2) | ((buf[1] & 0xc0) >> 6); - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_MP4_OBJECT_DESCRIPTOR: len=%d, OD_ID=%d\n", len, id); - if(buf[1] & 0x20) - { - i += buf[2] + 1; //url - mp_msg(MSGT_DEMUX, MSGL_V, "URL\n"); - } - else - { - i = 2; - - while(i < len) - { - j = parse_mp4_descriptors(pmt, &(buf[i]), len-i, elem); - mp_msg(MSGT_DEMUX, MSGL_V, "OBJD, NOW i = %d, j=%d, LEN=%d\n", i, j, len); - i += j; - } - } -} - - -static void parse_mp4_iod(pmt_t *pmt, uint8_t *buf, int len, void *elem) -{ - int i, j = 0; - mp4_od_t *iod = &(pmt->iod); - - iod->id = (buf[0] << 2) | ((buf[1] & 0xc0) >> 6); - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_MP4_IOD: len=%d, IOD_ID=%d\n", len, iod->id); - i = 2; - if(buf[1] & 0x20) - { - i += buf[2] + 1; //url - mp_msg(MSGT_DEMUX, MSGL_V, "URL\n"); - } - else - { - i = 7; - while(i < len) - { - j = parse_mp4_descriptors(pmt, &(buf[i]), len-i, elem); - mp_msg(MSGT_DEMUX, MSGL_V, "IOD, NOW i = %d, j=%d, LEN=%d\n", i, j, len); - i += j; - } - } -} - -static int parse_mp4_descriptors(pmt_t *pmt, uint8_t *buf, int len, void *elem) -{ - int tag, descr_len, i = 0, j = 0; - - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_MP4_DESCRIPTORS, len=%d\n", len); - if(! len) - return len; - - while(i < len) - { - tag = buf[i]; - j = len - i -1; - descr_len = get_mp4_desc_len(&(buf[i+1]), &j); - mp_msg(MSGT_DEMUX, MSGL_V, "TAG=%d (0x%x), DESCR_len=%d, len=%d, j=%d\n", tag, tag, descr_len, len, j); - if(descr_len > len - j+1) - { - mp_msg(MSGT_DEMUX, MSGL_V, "descriptor is too long, exit\n"); - return len; - } - i += j+1; - - switch(tag) - { - case 0x1: - parse_mp4_object_descriptor(pmt, &(buf[i]), descr_len, elem); - break; - case 0x2: - parse_mp4_iod(pmt, &(buf[i]), descr_len, elem); - break; - case 0x3: - parse_mp4_es_descriptor(pmt, &(buf[i]), descr_len); - break; - case 0x4: - parse_mp4_decoder_config_descriptor(pmt, &buf[i], descr_len, elem); - break; - case 0x05: - parse_mp4_decoder_specific_descriptor(&buf[i], descr_len, elem); - break; - case 0x6: - parse_mp4_slconfig_descriptor(&buf[i], descr_len, elem); - break; - default: - mp_msg(MSGT_DEMUX, MSGL_V, "Unsupported mp4 descriptor 0x%x\n", tag); - } - i += descr_len; - } - - return len; -} - -static ES_stream_t *new_pid(ts_priv_t *priv, int pid) -{ - ES_stream_t *tss; - - tss = calloc(sizeof(*tss), 1); - if(! tss) - return NULL; - tss->pid = pid; - tss->last_cc = -1; - tss->type = UNKNOWN; - tss->subtype = UNKNOWN; - tss->is_synced = 0; - tss->extradata = NULL; - tss->extradata_alloc = tss->extradata_len = 0; - priv->ts.pids[pid] = tss; - - return tss; -} - - -static int parse_program_descriptors(pmt_t *pmt, uint8_t *buf, uint16_t len) -{ - uint16_t i = 0, k, olen = len; - - while(len > 0) - { - mp_msg(MSGT_DEMUX, MSGL_V, "PROG DESCR, TAG=%x, LEN=%d(%x)\n", buf[i], buf[i+1], buf[i+1]); - if(buf[i+1] > len-2) - { - mp_msg(MSGT_DEMUX, MSGL_V, "ERROR, descriptor len is too long, skipping\n"); - return olen; - } - - if(buf[i] == 0x1d) - { - if(buf[i+3] == 2) //buggy versions of vlc muxer make this non-standard mess (missing iod_scope) - k = 3; - else - k = 4; //this is standard compliant - parse_mp4_descriptors(pmt, &buf[i+k], (int) buf[i+1]-(k-2), NULL); - } - - len -= 2 + buf[i+1]; - } - - return olen; -} - -static int parse_descriptors(struct pmt_es_t *es, uint8_t *ptr) -{ - int j, descr_len, len; - - j = 0; - len = es->descr_length; - while(len > 2) - { - descr_len = ptr[j+1]; - mp_msg(MSGT_DEMUX, MSGL_V, "...descr id: 0x%x, len=%d\n", ptr[j], descr_len); - if(descr_len > len) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "INVALID DESCR LEN for tag %02x: %d vs %d max, EXIT LOOP\n", ptr[j], descr_len, len); - return -1; - } - - - if(ptr[j] == 0x6a || ptr[j] == 0x7a) //A52 Descriptor - { - if(es->type == 0x6) - { - es->type = AUDIO_A52; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "DVB A52 Descriptor\n"); - } - } - else if(ptr[j] == 0x7b) //DVB DTS Descriptor - { - if(es->type == 0x6) - { - es->type = AUDIO_DTS; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "DVB DTS Descriptor\n"); - } - } - else if(ptr[j] == 0x56) // Teletext - { - if(descr_len >= 5) { - memcpy(es->lang, ptr+j+2, 3); - es->lang[3] = 0; - } - es->type = SPU_TELETEXT; - } - else if(ptr[j] == 0x59) //Subtitling Descriptor - { - uint8_t subtype; - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "Subtitling Descriptor\n"); - if(descr_len < 8) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "Descriptor length too short for DVB Subtitle Descriptor: %d, SKIPPING\n", descr_len); - } - else - { - memcpy(es->lang, &ptr[j+2], 3); - es->lang[3] = 0; - subtype = ptr[j+5]; - if( - (subtype >= 0x10 && subtype <= 0x13) || - (subtype >= 0x20 && subtype <= 0x23) - ) - { - es->type = SPU_DVB; - //page parameters: compo page 2 bytes, ancillary page 2 bytes - } - else - es->type = UNKNOWN; - } - } - else if(ptr[j] == 0x50) //Component Descriptor - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "Component Descriptor\n"); - memcpy(es->lang, &ptr[j+5], 3); - es->lang[3] = 0; - } - else if(ptr[j] == 0xa) //Language Descriptor - { - memcpy(es->lang, &ptr[j+2], 3); - es->lang[3] = 0; - mp_msg(MSGT_DEMUX, MSGL_V, "Language Descriptor: %s\n", es->lang); - } - else if(ptr[j] == 0x5) //Registration Descriptor (looks like e fourCC :) ) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "Registration Descriptor\n"); - if(descr_len < 4) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "Registration Descriptor length too short: %d, SKIPPING\n", descr_len); - } - else - { - char *d; - memcpy(es->format_descriptor, &ptr[j+2], 4); - es->format_descriptor[4] = 0; - - d = &ptr[j+2]; - if(d[0] == 'A' && d[1] == 'C' && d[2] == '-' && d[3] == '3') - { - es->type = AUDIO_A52; - } - else if(d[0] == 'D' && d[1] == 'T' && d[2] == 'S' && d[3] == '1') - { - es->type = AUDIO_DTS; - } - else if(d[0] == 'D' && d[1] == 'T' && d[2] == 'S' && d[3] == '2') - { - es->type = AUDIO_DTS; - } - else if(d[0] == 'V' && d[1] == 'C' && d[2] == '-' && d[3] == '1') - { - es->type = VIDEO_VC1; - } - else if(d[0] == 'd' && d[1] == 'r' && d[2] == 'a' && d[3] == 'c') - { - es->type = VIDEO_DIRAC; - } - else if(d[0] == 'B' && d[1] == 'S' && d[2] == 'S' && d[3] == 'D') - { - es->type = AUDIO_S302M; - } - else - es->type = UNKNOWN; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "FORMAT %s\n", es->format_descriptor); - } - } - else if(ptr[j] == 0x1e || ptr[j] == 0x1f) - { - // 0x1f is FMC, but currently it is easiest to handle them the same way - es->mp4_es_id = (ptr[j+2] << 8) | ptr[j+3]; - mp_msg(MSGT_DEMUX, MSGL_V, "SL Descriptor: ES_ID: %d(%x), pid: %d\n", es->mp4_es_id, es->mp4_es_id, es->pid); - } - else - mp_msg(MSGT_DEMUX, MSGL_DBG2, "Unknown descriptor 0x%x, SKIPPING\n", ptr[j]); - - len -= 2 + descr_len; - j += 2 + descr_len; - } - - return 1; -} - -static int parse_sl_section(pmt_t *pmt, ts_section_t *section, int is_start, unsigned char *buff, int size) -{ - int tid, len, skip; - uint8_t *ptr; - skip = collect_section(section, is_start, buff, size); - if(! skip) - return 0; - - ptr = &(section->buffer[skip]); - tid = ptr[0]; - len = ((ptr[1] & 0x0f) << 8) | ptr[2]; - mp_msg(MSGT_DEMUX, MSGL_V, "TABLEID: %d (av. %d), skip=%d, LEN: %d\n", tid, section->buffer_len, skip, len); - if(len > 4093 || section->buffer_len < len || tid != 5) - { - mp_msg(MSGT_DEMUX, MSGL_V, "SECTION TOO LARGE or wrong section type, EXIT\n"); - return 0; - } - - if(! (ptr[5] & 1)) - return 0; - - //8 is the current position, len - 9 is the amount of data available - parse_mp4_descriptors(pmt, &ptr[8], len - 9, NULL); - - return 1; -} - -static int parse_pmt(ts_priv_t * priv, uint16_t progid, uint16_t pid, int is_start, unsigned char *buff, int size) -{ - unsigned char *base, *es_base; - pmt_t *pmt; - int32_t idx, es_count, section_bytes; - uint8_t m=0; - int skip; - ts_section_t *section; - ES_stream_t *tss; - int i; - - idx = progid_idx_in_pmt(priv, progid); - - if(idx == -1) - { - priv->pmt = realloc_struct(priv->pmt, priv->pmt_cnt + 1, sizeof(pmt_t)); - if(!priv->pmt) - { - int sz = (priv->pmt_cnt + 1) * sizeof(pmt_t); - priv->pmt_cnt = 0; - mp_msg(MSGT_DEMUX, MSGL_ERR, "PARSE_PMT: COULDN'T REALLOC %d bytes, NEXT\n", sz); - return 0; - } - idx = priv->pmt_cnt; - memset(&(priv->pmt[idx]), 0, sizeof(pmt_t)); - priv->pmt_cnt++; - priv->pmt[idx].progid = progid; - } - - pmt = &(priv->pmt[idx]); - - section = &(pmt->section); - skip = collect_section(section, is_start, buff, size); - if(! skip) - return 0; - - base = &(section->buffer[skip]); - - mp_msg(MSGT_DEMUX, MSGL_V, "FILL_PMT(prog=%d), PMT_len: %d, IS_START: %d, TS_PID: %d, SIZE=%d, M=%d, ES_CNT=%d, IDX=%d, PMT_PTR=%p\n", - progid, pmt->section.buffer_len, is_start, pid, size, m, pmt->es_cnt, idx, pmt); - - pmt->table_id = base[0]; - if(pmt->table_id != 2) - return -1; - pmt->ssi = base[1] & 0x80; - pmt->section_length = (((base[1] & 0xf) << 8 ) | base[2]); - pmt->version_number = (base[5] >> 1) & 0x1f; - pmt->curr_next = (base[5] & 1); - pmt->section_number = base[6]; - pmt->last_section_number = base[7]; - pmt->PCR_PID = ((base[8] & 0x1f) << 8 ) | base[9]; - pmt->prog_descr_length = ((base[10] & 0xf) << 8 ) | base[11]; - if(pmt->prog_descr_length > pmt->section_length - 9) - { - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_PMT, INVALID PROG_DESCR LENGTH (%d vs %d)\n", pmt->prog_descr_length, pmt->section_length - 9); - return -1; - } - - if(pmt->prog_descr_length) - parse_program_descriptors(pmt, &base[12], pmt->prog_descr_length); - - es_base = &base[12 + pmt->prog_descr_length]; //the beginning of th ES loop - - section_bytes= pmt->section_length - 13 - pmt->prog_descr_length; - es_count = 0; - - while(section_bytes >= 5) - { - int es_pid, es_type; - - es_type = es_base[0]; - es_pid = ((es_base[1] & 0x1f) << 8) | es_base[2]; - - idx = es_pid_in_pmt(pmt, es_pid); - if(idx == -1) - { - pmt->es = realloc_struct(pmt->es, pmt->es_cnt + 1, sizeof(struct pmt_es_t)); - if(!pmt->es) - { - int sz = sizeof(struct pmt_es_t) * (pmt->es_cnt + 1); - pmt->es_cnt = 0; - mp_msg(MSGT_DEMUX, MSGL_ERR, "PARSE_PMT, COULDN'T ALLOCATE %d bytes for PMT_ES\n", sz); - continue; - } - idx = pmt->es_cnt; - memset(&(pmt->es[idx]), 0, sizeof(struct pmt_es_t)); - pmt->es_cnt++; - } - - pmt->es[idx].descr_length = ((es_base[3] & 0xf) << 8) | es_base[4]; - - - if(pmt->es[idx].descr_length > section_bytes - 5) - { - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_PMT, ES_DESCR_LENGTH TOO LARGE %d > %d, EXIT\n", - pmt->es[idx].descr_length, section_bytes - 5); - return -1; - } - - - pmt->es[idx].pid = es_pid; - if(es_type != 0x6) - pmt->es[idx].type = UNKNOWN; - else - pmt->es[idx].type = es_type; - - parse_descriptors(&pmt->es[idx], &es_base[5]); - - switch(es_type) - { - case 1: - pmt->es[idx].type = VIDEO_MPEG1; - break; - case 2: - pmt->es[idx].type = VIDEO_MPEG2; - break; - case 3: - case 4: - pmt->es[idx].type = AUDIO_MP2; - break; - case 6: - if(pmt->es[idx].type == 0x6) //this could have been ovrwritten by parse_descriptors - pmt->es[idx].type = UNKNOWN; - break; - case 0x10: - pmt->es[idx].type = VIDEO_MPEG4; - break; - case 0x0f: - pmt->es[idx].type = AUDIO_AAC; - break; - case 0x11: - pmt->es[idx].type = AUDIO_AAC_LATM; - for (i = 0; i < pmt->mp4es_cnt; i++) - if (pmt->mp4es[i].id == pmt->es[idx].mp4_es_id && - pmt->mp4es[i].decoder.object_type == AUDIO_AAC) - pmt->es[idx].type = AUDIO_AAC; - break; - case 0x1b: - pmt->es[idx].type = VIDEO_H264; - break; - case 0x12: - pmt->es[idx].type = SL_PES_STREAM; - break; - case 0x13: - pmt->es[idx].type = SL_SECTION; - break; - case 0x80: - pmt->es[idx].type = AUDIO_PCM_BR; - break; - case 0x81: - pmt->es[idx].type = AUDIO_A52; - break; - case 0x8A: - case 0x82: - case 0x85: - case 0x86: - pmt->es[idx].type = AUDIO_DTS; - break; - case 0x90: - pmt->es[idx].type = SPU_PGS; - break; - case 0xD1: - pmt->es[idx].type = VIDEO_DIRAC; - break; - case 0xEA: - pmt->es[idx].type = VIDEO_VC1; - break; - default: - mp_msg(MSGT_DEMUX, MSGL_DBG2, "UNKNOWN ES TYPE=0x%x\n", es_type); - pmt->es[idx].type = UNKNOWN; - } - - tss = priv->ts.pids[es_pid]; //an ES stream - if(tss == NULL) - { - tss = new_pid(priv, es_pid); - if(tss) - tss->type = pmt->es[idx].type; - } - - section_bytes -= 5 + pmt->es[idx].descr_length; - mp_msg(MSGT_DEMUX, MSGL_V, "PARSE_PMT(%d INDEX %d), STREAM: %d, FOUND pid=0x%x (%d), type=0x%x, ES_DESCR_LENGTH: %d, bytes left: %d\n", - progid, idx, es_count, pmt->es[idx].pid, pmt->es[idx].pid, pmt->es[idx].type, pmt->es[idx].descr_length, section_bytes); - - - es_base += 5 + pmt->es[idx].descr_length; - - es_count++; - } - - mp_msg(MSGT_DEMUX, MSGL_V, "----------------------------\n"); - return 1; -} - -static pmt_t* pmt_of_pid(ts_priv_t *priv, int pid, mp4_decoder_config_t **mp4_dec) -{ - int32_t i, j, k; - - if(priv->pmt) - { - for(i = 0; i < priv->pmt_cnt; i++) - { - if(priv->pmt[i].es && priv->pmt[i].es_cnt) - { - for(j = 0; j < priv->pmt[i].es_cnt; j++) - { - if(priv->pmt[i].es[j].pid == pid) - { - //search mp4_es_id - if(priv->pmt[i].es[j].mp4_es_id) - { - for(k = 0; k < priv->pmt[i].mp4es_cnt; k++) - { - if(priv->pmt[i].mp4es[k].id == priv->pmt[i].es[j].mp4_es_id) - { - *mp4_dec = &(priv->pmt[i].mp4es[k].decoder); - break; - } - } - } - - return &(priv->pmt[i]); - } - } - } - } - } - - return NULL; -} - - -static int32_t pid_type_from_pmt(ts_priv_t *priv, int pid) -{ - int32_t pmt_idx, pid_idx, i, j; - - pmt_idx = progid_idx_in_pmt(priv, priv->prog); - - if(pmt_idx != -1) - { - pid_idx = es_pid_in_pmt(&(priv->pmt[pmt_idx]), pid); - if(pid_idx != -1) - return priv->pmt[pmt_idx].es[pid_idx].type; - } - //else - //{ - for(i = 0; i < priv->pmt_cnt; i++) - { - pmt_t *pmt = &(priv->pmt[i]); - for(j = 0; j < pmt->es_cnt; j++) - if(pmt->es[j].pid == pid) - return pmt->es[j].type; - } - //} - - return UNKNOWN; -} - - -static uint8_t *pid_lang_from_pmt(ts_priv_t *priv, int pid) -{ - int32_t pmt_idx, pid_idx, i, j; - - pmt_idx = progid_idx_in_pmt(priv, priv->prog); - - if(pmt_idx != -1) - { - pid_idx = es_pid_in_pmt(&(priv->pmt[pmt_idx]), pid); - if(pid_idx != -1) - return priv->pmt[pmt_idx].es[pid_idx].lang; - } - else - { - for(i = 0; i < priv->pmt_cnt; i++) - { - pmt_t *pmt = &(priv->pmt[i]); - for(j = 0; j < pmt->es_cnt; j++) - if(pmt->es[j].pid == pid) - return pmt->es[j].lang; - } - } - - return NULL; -} - - -static int fill_packet(demuxer_t *demuxer, demux_stream_t *ds, demux_packet_t **dp, int *dp_offset, TS_stream_info *si) -{ - int ret = 0; - - if(*dp && *dp_offset <= 0) - { - free_demux_packet(*dp); - *dp = NULL; - } - if(*dp) - { - ret = *dp_offset; - resize_demux_packet(*dp, ret); //shrinked to the right size - ds_add_packet(ds, *dp); - mp_msg(MSGT_DEMUX, MSGL_DBG2, "ADDED %d bytes to %s fifo, PTS=%.3f\n", ret, (ds == demuxer->audio ? "audio" : (ds == demuxer->video ? "video" : "sub")), (*dp)->pts); - if(si) - { - float diff = (*dp)->pts - si->last_pts; - float dur; - - if(abs(diff) > 1) //1 second, there's a discontinuity - { - si->duration += si->last_pts - si->first_pts; - si->first_pts = si->last_pts = (*dp)->pts; - } - else - { - si->last_pts = (*dp)->pts; - } - si->size += ret; - dur = si->duration + (si->last_pts - si->first_pts); - - if(dur > 0 && ds == demuxer->video) - { - ts_priv_t * priv = (ts_priv_t*) demuxer->priv; - if(dur > 1) //otherwise it may be unreliable - priv->vbitrate = (uint32_t) ((float) si->size / dur); - } - } - } - - *dp = NULL; - *dp_offset = 0; - - return ret; -} - -static int fill_extradata(mp4_decoder_config_t * mp4_dec, ES_stream_t *tss) -{ - uint8_t *tmp; - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "MP4_dec: %p, pid: %d\n", mp4_dec, tss->pid); - - if(mp4_dec->buf_size > tss->extradata_alloc) - { - tmp = realloc(tss->extradata, mp4_dec->buf_size); - if(!tmp) - return 0; - tss->extradata = tmp; - tss->extradata_alloc = mp4_dec->buf_size; - } - memcpy(tss->extradata, mp4_dec->buf, mp4_dec->buf_size); - tss->extradata_len = mp4_dec->buf_size; - mp_msg(MSGT_DEMUX, MSGL_V, "EXTRADATA: %p, alloc=%d, len=%d\n", tss->extradata, tss->extradata_alloc, tss->extradata_len); - - return tss->extradata_len; -} - -// 0 = EOF or no stream found -// else = [-] number of bytes written to the packet -static int ts_parse(demuxer_t *demuxer , ES_stream_t *es, unsigned char *packet, int probe) -{ - ES_stream_t *tss; - int buf_size, is_start, pid, base; - int len, cc, cc_ok av_unused, afc, retv = 0, is_video, is_audio, is_sub; - ts_priv_t * priv = (ts_priv_t*) demuxer->priv; - stream_t *stream = demuxer->stream; - char *p; - demux_stream_t *ds = NULL; - demux_packet_t **dp = NULL; - int *dp_offset = 0, *buffer_size = 0; - int32_t progid, pid_type, bad, ts_error; - int junk = 0, rap_flag = 0; - pmt_t *pmt; - mp4_decoder_config_t *mp4_dec; - TS_stream_info *si; - - - memset(es, 0, sizeof(*es)); - while(1) - { - bad = ts_error = 0; - ds = NULL; - dp = NULL; - dp_offset = buffer_size = NULL; - rap_flag = 0; - mp4_dec = NULL; - es->is_synced = 0; - es->lang[0] = 0; - si = NULL; - - junk = priv->ts.packet_size - TS_PACKET_SIZE; - buf_size = priv->ts.packet_size - junk; - - if(stream_eof(stream)) - { - if(! probe) - { - ts_dump_streams(priv); - demuxer->filepos = stream_tell(demuxer->stream); - } - - return 0; - } - - - if(! ts_sync(stream)) - { - mp_msg(MSGT_DEMUX, MSGL_INFO, "TS_PARSE: COULDN'T SYNC\n"); - return 0; - } - - len = stream_read(stream, &packet[1], 3); - if (len != 3) - return 0; - buf_size -= 4; - - if((packet[1] >> 7) & 0x01) //transport error - ts_error = 1; - - - is_start = packet[1] & 0x40; - pid = ((packet[1] & 0x1f) << 8) | packet[2]; - - tss = priv->ts.pids[pid]; //an ES stream - if(tss == NULL) - { - tss = new_pid(priv, pid); - if(tss == NULL) - continue; - } - - cc = (packet[3] & 0xf); - cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc)); - tss->last_cc = cc; - - bad = ts_error; // || (! cc_ok); - if(bad) - { - if(priv->keep_broken == 0) - { - stream_skip(stream, buf_size-1+junk); - continue; - } - - is_start = 0; //queued to the packet data - } - - if(is_start) - tss->is_synced = 1; - - if((!is_start && !tss->is_synced) || ((pid > 1) && (pid < 16)) || (pid == 8191)) //invalid pid - { - stream_skip(stream, buf_size-1+junk); - continue; - } - - - afc = (packet[3] >> 4) & 3; - if(! (afc % 2)) //no payload in this TS packet - { - stream_skip(stream, buf_size-1+junk); - continue; - } - - if(afc > 1) - { - int c; - c = stream_read_char(stream); - buf_size--; - if(c < 0 || c > 183) //broken from the stream layer or invalid - { - stream_skip(stream, buf_size-1+junk); - continue; - } - - //c==0 is allowed! - if(c > 0) - { - uint8_t pcrbuf[188]; - int flags = stream_read_char(stream); - int has_pcr; - rap_flag = (flags & 0x40) >> 6; - has_pcr = flags & 0x10; - - buf_size--; - c--; - stream_read(stream, pcrbuf, c); - - if(has_pcr) - { - int pcr_pid = prog_pcr_pid(priv, priv->prog); - if(pcr_pid == pid) - { - uint64_t pcr, pcr_ext; - - pcr = (int64_t)(pcrbuf[0]) << 25; - pcr |= pcrbuf[1] << 17 ; - pcr |= (pcrbuf[2]) << 9; - pcr |= pcrbuf[3] << 1 ; - pcr |= (pcrbuf[4] & 0x80) >> 7; - - pcr_ext = (pcrbuf[4] & 0x01) << 8; - pcr_ext |= pcrbuf[5]; - - pcr = pcr * 300 + pcr_ext; - - demuxer->reference_clock = (double)pcr/(double)27000000.0; - } - } - - buf_size -= c; - if(buf_size == 0) - continue; - } - } - - //find the program that the pid belongs to; if (it's the right one or -1) && pid_type==SL_SECTION - //call parse_sl_section() - pmt = pmt_of_pid(priv, pid, &mp4_dec); - if(mp4_dec) - { - fill_extradata(mp4_dec, tss); - if(IS_VIDEO(mp4_dec->object_type) || IS_AUDIO(mp4_dec->object_type)) - { - tss->type = SL_PES_STREAM; - tss->subtype = mp4_dec->object_type; - } - } - - - //TABLE PARSING - - base = priv->ts.packet_size - buf_size; - - priv->last_pid = pid; - - is_video = IS_VIDEO(tss->type) || (tss->type==SL_PES_STREAM && IS_VIDEO(tss->subtype)); - is_audio = IS_AUDIO(tss->type) || (tss->type==SL_PES_STREAM && IS_AUDIO(tss->subtype)) || (tss->type == PES_PRIVATE1); - is_sub = IS_SUB(tss->type); - pid_type = pid_type_from_pmt(priv, pid); - - // PES CONTENT STARTS HERE - if(! probe) - { - if((is_video || is_audio || is_sub) && is_start) - ts_add_stream(demuxer, tss); - - if(is_video && (demuxer->video->id == priv->ts.streams[pid].id)) - { - ds = demuxer->video; - - dp = &priv->fifo[1].pack; - dp_offset = &priv->fifo[1].offset; - buffer_size = &priv->fifo[1].buffer_size; - si = &priv->vstr; - } - else if(is_audio && (demuxer->audio->id == priv->ts.streams[pid].id)) - { - ds = demuxer->audio; - - dp = &priv->fifo[0].pack; - dp_offset = &priv->fifo[0].offset; - buffer_size = &priv->fifo[0].buffer_size; - si = &priv->astr; - } - else if(is_sub) - { - sh_sub_t *sh_sub = demuxer->sub->sh; - - if(sh_sub && sh_sub->gsh->demuxer_id == tss->pid) - { - ds = demuxer->sub; - - dp = &priv->fifo[2].pack; - dp_offset = &priv->fifo[2].offset; - buffer_size = &priv->fifo[2].buffer_size; - } - else - { - stream_skip(stream, buf_size+junk); - continue; - } - } - - //IS IT TIME TO QUEUE DATA to the dp_packet? - if(is_start && (dp != NULL)) - { - retv = fill_packet(demuxer, ds, dp, dp_offset, si); - } - - - if(dp && *dp == NULL) - { - if(*buffer_size > MAX_PACK_BYTES) - *buffer_size = MAX_PACK_BYTES; - *dp = new_demux_packet(*buffer_size); //es->size - *dp_offset = 0; - if(! *dp) - { - fprintf(stderr, "fill_buffer, NEW_ADD_PACKET(%d)FAILED\n", *buffer_size); - continue; - } - mp_msg(MSGT_DEMUX, MSGL_DBG2, "CREATED DP(%d)\n", *buffer_size); - } - } - - - if(probe || !dp) //dp is NULL for tables and sections - { - p = &packet[base]; - } - else //feeding - { - if(*dp_offset + buf_size > *buffer_size) - { - *buffer_size = *dp_offset + buf_size + TS_FEC_PACKET_SIZE; - resize_demux_packet(*dp, *buffer_size); - } - p = &((*dp)->buffer[*dp_offset]); - } - - len = stream_read(stream, p, buf_size); - if(len < buf_size) - { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "\r\nts_parse() couldn't read enough data: %d < %d\r\n", len, buf_size); - continue; - } - stream_skip(stream, junk); - - if(pid == 0) - { - parse_pat(priv, is_start, p, buf_size); - continue; - } - else if((tss->type == SL_SECTION) && pmt) - { - int k, mp4_es_id = -1; - ts_section_t *section; - for(k = 0; k < pmt->mp4es_cnt; k++) - { - if(pmt->mp4es[k].decoder.object_type == MP4_OD && pmt->mp4es[k].decoder.stream_type == MP4_OD) - mp4_es_id = pmt->mp4es[k].id; - } - mp_msg(MSGT_DEMUX, MSGL_DBG2, "MP4ESID: %d\n", mp4_es_id); - for(k = 0; k < pmt->es_cnt; k++) - { - if(pmt->es[k].mp4_es_id == mp4_es_id) - { - section = &(tss->section); - parse_sl_section(pmt, section, is_start, &packet[base], buf_size); - } - } - continue; - } - else - { - progid = prog_id_in_pat(priv, pid); - if(progid != -1) - { - if(pid != demuxer->video->id && pid != demuxer->audio->id && pid != demuxer->sub->id) - { - parse_pmt(priv, progid, pid, is_start, &packet[base], buf_size); - continue; - } - else - mp_msg(MSGT_DEMUX, MSGL_ERR, "Argh! Data pid %d used in the PMT, Skipping PMT parsing!\n", pid); - } - } - - if(!probe && !dp) - continue; - - if(is_start) - { - uint8_t *lang = NULL; - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "IS_START\n"); - - len = pes_parse2(p, buf_size, es, pid_type, pmt, pid); - if(! len) - { - tss->is_synced = 0; - continue; - } - es->pid = tss->pid; - tss->is_synced |= es->is_synced || rap_flag; - tss->payload_size = es->payload_size; - - if((is_sub || is_audio) && (lang = pid_lang_from_pmt(priv, es->pid))) - { - memcpy(es->lang, lang, 3); - es->lang[3] = 0; - } - else - es->lang[0] = 0; - - if(probe) - { - if(es->type == UNKNOWN) - return 0; - - tss->type = es->type; - tss->subtype = es->subtype; - - return 1; - } - else - { - if(es->pts == 0.0) - es->pts = tss->pts = tss->last_pts; - else - tss->pts = tss->last_pts = es->pts; - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "ts_parse, NEW pid=%d, PSIZE: %u, type=%X, start=%p, len=%d\n", - es->pid, es->payload_size, es->type, es->start, es->size); - - demuxer->filepos = stream_tell(demuxer->stream) - es->size; - - if(es->size < 0 || es->size > buf_size) { - mp_msg(MSGT_DEMUX, MSGL_ERR, "Broken ES packet size\n"); - es->size = 0; - } - memmove(p, es->start, es->size); - *dp_offset += es->size; - (*dp)->keyframe = 0; - (*dp)->pos = stream_tell(demuxer->stream); - (*dp)->pts = es->pts; - // subtitle packets must be returned immediately if possible - if (is_sub && !tss->payload_size) - retv = fill_packet(demuxer, ds, dp, dp_offset, si); - - if(retv > 0) - return retv; - else - continue; - } - } - else - { - uint16_t sz; - - es->pid = tss->pid; - es->type = tss->type; - es->subtype = tss->subtype; - es->pts = tss->pts = tss->last_pts; - es->start = &packet[base]; - - - if(tss->payload_size > 0) - { - sz = FFMIN(tss->payload_size, buf_size); - tss->payload_size -= sz; - es->size = sz; - } - else - { - if(is_video) - { - sz = es->size = buf_size; - } - else - { - continue; - } - } - - - if(! probe) - { - *dp_offset += sz; - - // subtitle packets must be returned immediately if possible - if(*dp_offset >= MAX_PACK_BYTES || (is_sub && !tss->payload_size)) - { - (*dp)->pts = tss->last_pts; - retv = fill_packet(demuxer, ds, dp, dp_offset, si); - return 1; - } - - continue; - } - else - { - memmove(es->start, p, sz); - - if(es->size) - return es->size; - else - continue; - } - } - } - - return 0; -} - - -static void reset_fifos(demuxer_t *demuxer, int a, int v, int s) -{ - ts_priv_t* priv = demuxer->priv; - if(a) - { - if(priv->fifo[0].pack != NULL) - { - free_demux_packet(priv->fifo[0].pack); - priv->fifo[0].pack = NULL; - } - priv->fifo[0].offset = 0; - } - - if(v) - { - if(priv->fifo[1].pack != NULL) - { - free_demux_packet(priv->fifo[1].pack); - priv->fifo[1].pack = NULL; - } - priv->fifo[1].offset = 0; - } - - if(s) - { - if(priv->fifo[2].pack != NULL) - { - free_demux_packet(priv->fifo[2].pack); - priv->fifo[2].pack = NULL; - } - priv->fifo[2].offset = 0; - } - demuxer->reference_clock = MP_NOPTS_VALUE; -} - - -static void demux_seek_ts(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, 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; - ts_priv_t * priv = (ts_priv_t*) demuxer->priv; - int i, video_stats; - int64_t newpos; - - //================= seek in MPEG-TS ========================== - - ts_dump_streams(demuxer->priv); - reset_fifos(demuxer, sh_audio != NULL, sh_video != NULL, demuxer->sub->id > 0); - - demux_flush(demuxer); - - - - video_stats = (sh_video != NULL); - if(video_stats) - { - mp_msg(MSGT_DEMUX, MSGL_V, "IBPS: %d, vb: %d\r\n", sh_video->i_bps, priv->vbitrate); - if(priv->vbitrate) - video_stats = priv->vbitrate; - else - video_stats = sh_video->i_bps; - } - - newpos = (flags & SEEK_ABSOLUTE) ? demuxer->movi_start : demuxer->filepos; - if(flags & SEEK_FACTOR) // float seek 0..1 - newpos+=(demuxer->movi_end-demuxer->movi_start)*rel_seek_secs; - else - { - // time seek (secs) - if(! video_stats) // unspecified or VBR - newpos += 2324*75*rel_seek_secs; // 174.3 kbyte/sec - else - newpos += video_stats*rel_seek_secs; - } - - - if(newpos < demuxer->movi_start) - newpos = demuxer->movi_start; //begininng of stream - - stream_seek(demuxer->stream, newpos); - for(i = 0; i < NB_PID_MAX; i++) - if(priv->ts.pids[i] != NULL) - priv->ts.pids[i]->is_synced = 0; - - videobuf_code_len = 0; - - if(sh_video != NULL) - ds_fill_buffer(d_video); - - if(sh_audio != NULL) - { - ds_fill_buffer(d_audio); - } - - while(sh_video != NULL) - { - if(sh_audio && !d_audio->eof && d_video->pts && d_audio->pts) - { - double a_pts=d_audio->pts; - a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(double)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((sh_video->format == VIDEO_MPEG1) || (sh_video->format == VIDEO_MPEG2)) - { - if(i==0x1B3 || i==0x1B8) break; // found it! - } - else if((sh_video->format == VIDEO_MPEG4) && (i==0x1B6)) - break; - else if(sh_video->format == VIDEO_VC1 && (i==0x10E || i==0x10F)) - break; - else //H264 - { - if((i & ~0x60) == 0x105 || (i & ~0x60) == 0x107) break; - } - - if(!i || !skip_video_packet(d_video)) break; // EOF? - } -} - - -static int demux_ts_fill_buffer(demuxer_t * demuxer, demux_stream_t *ds) -{ - ES_stream_t es; - ts_priv_t *priv = (ts_priv_t *)demuxer->priv; - - return -ts_parse(demuxer, &es, priv->packet, 0); -} - - -static int ts_check_file_dmx(demuxer_t *demuxer) -{ - return ts_check_file(demuxer) ? DEMUXER_TYPE_MPEG_TS : 0; -} - -static int is_usable_program(ts_priv_t *priv, pmt_t *pmt) -{ - int j; - - for(j = 0; j < pmt->es_cnt; j++) - { - if(priv->ts.pids[pmt->es[j].pid] == NULL || priv->ts.streams[pmt->es[j].pid].sh == NULL) - continue; - if( - priv->ts.streams[pmt->es[j].pid].type == TYPE_VIDEO || - priv->ts.streams[pmt->es[j].pid].type == TYPE_AUDIO - ) - return 1; - } - - return 0; -} - -static int demux_ts_control(demuxer_t *demuxer, int cmd, void *arg) -{ - ts_priv_t* priv = (ts_priv_t *)demuxer->priv; - - switch(cmd) - { - case DEMUXER_CTRL_SWITCH_AUDIO: - case DEMUXER_CTRL_SWITCH_VIDEO: - { - void *sh = NULL; - int i, n; - int reftype, areset = 0, vreset = 0; - demux_stream_t *ds; - - if(cmd == DEMUXER_CTRL_SWITCH_VIDEO) - { - reftype = TYPE_VIDEO; - ds = demuxer->video; - vreset = 1; - } - else - { - reftype = TYPE_AUDIO; - ds = demuxer->audio; - areset = 1; - } - n = *((int*)arg); - if(n == -2) - { - reset_fifos(demuxer, areset, vreset, 0); - ds->id = -2; - ds->sh = NULL; - ds_free_packs(ds); - *((int*)arg) = ds->id; - return DEMUXER_CTRL_OK; - } - - if(n < 0) - { - for(i = 0; i < 8192; i++) - { - if(priv->ts.streams[i].id == ds->id && priv->ts.streams[i].type == reftype) - break; - } - - while(!sh) - { - i = (i+1) % 8192; - if(priv->ts.streams[i].type == reftype) - { - if(priv->ts.streams[i].id == ds->id) //we made a complete loop - break; - sh = priv->ts.streams[i].sh; - } - } - } - else //audio track <n> - { - if (n >= 8192 || priv->ts.streams[n].type != reftype) return DEMUXER_CTRL_NOTIMPL; - i = n; - sh = priv->ts.streams[i].sh; - } - - if(sh) - { - if(ds->id != priv->ts.streams[i].id) - reset_fifos(demuxer, areset, vreset, 0); - ds->id = priv->ts.streams[i].id; - ds->sh = sh; - ds_free_packs(ds); - mp_msg(MSGT_DEMUX, MSGL_V, "\r\ndemux_ts, switched to audio pid %d, id: %d, sh: %p\r\n", i, ds->id, sh); - } - - *((int*)arg) = ds->id; - return DEMUXER_CTRL_OK; - } - - case DEMUXER_CTRL_IDENTIFY_PROGRAM: //returns in prog->{aid,vid} the new ids that comprise a program - { - int i, j, cnt=0; - int vid_done=0, aid_done=0; - pmt_t *pmt = NULL; - demux_program_t *prog = arg; - - if(priv->pmt_cnt < 2) - return DEMUXER_CTRL_NOTIMPL; - - if(prog->progid == -1) - { - int cur_pmt_idx = 0; - - for(i = 0; i < priv->pmt_cnt; i++) - if(priv->pmt[i].progid == priv->prog) - { - cur_pmt_idx = i; - break; - } - - i = (cur_pmt_idx + 1) % priv->pmt_cnt; - while(i != cur_pmt_idx) - { - pmt = &priv->pmt[i]; - cnt = is_usable_program(priv, pmt); - if(cnt) - break; - i = (i + 1) % priv->pmt_cnt; - } - } - else - { - for(i = 0; i < priv->pmt_cnt; i++) - if(priv->pmt[i].progid == prog->progid) - { - pmt = &priv->pmt[i]; //required program - cnt = is_usable_program(priv, pmt); - } - } - - if(!cnt) - return DEMUXER_CTRL_NOTIMPL; - - //finally some food - prog->aid = prog->vid = -2; //no audio and no video by default - for(j = 0; j < pmt->es_cnt; j++) - { - if(priv->ts.pids[pmt->es[j].pid] == NULL || priv->ts.streams[pmt->es[j].pid].sh == NULL) - continue; - - if(!vid_done && priv->ts.streams[pmt->es[j].pid].type == TYPE_VIDEO) - { - vid_done = 1; - prog->vid = pmt->es[j].pid; - } - else if(!aid_done && priv->ts.streams[pmt->es[j].pid].type == TYPE_AUDIO) - { - aid_done = 1; - prog->aid = pmt->es[j].pid; - } - } - - priv->prog = prog->progid = pmt->progid; - return DEMUXER_CTRL_OK; - } - - default: - return DEMUXER_CTRL_NOTIMPL; - } -} - - -const demuxer_desc_t demuxer_desc_mpeg_ts = { - "MPEG-TS demuxer", - "mpegts", - "TS", - "Nico Sabbi", - "", - DEMUXER_TYPE_MPEG_TS, - 0, // unsafe autodetect - ts_check_file_dmx, - demux_ts_fill_buffer, - demux_open_ts, - demux_close_ts, - demux_seek_ts, - demux_ts_control -}; diff --git a/demux/demux_ts.h b/demux/demux_ts.h deleted file mode 100644 index 37bddb86da..0000000000 --- a/demux/demux_ts.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_DEMUX_TS_H -#define MPLAYER_DEMUX_TS_H - -#define TS_MAX_PROBE_SIZE 2000000 - -#endif /* MPLAYER_DEMUX_TS_H */ diff --git a/demux/extension.c b/demux/extension.c index 71b5bf8f4d..30cb592b9f 100644 --- a/demux/extension.c +++ b/demux/extension.c @@ -38,17 +38,17 @@ static struct { const char *extension; int demuxer_type; } extensions_table[] = { - { "vob", DEMUXER_TYPE_MPEG_PS }, - { "m2v", DEMUXER_TYPE_MPEG_PS }, - { "avi", DEMUXER_TYPE_AVI }, - { "asx", DEMUXER_TYPE_ASF }, - { "asf", DEMUXER_TYPE_ASF }, - { "wmv", DEMUXER_TYPE_ASF }, - { "wma", DEMUXER_TYPE_ASF }, + { "vob", DEMUXER_TYPE_LAVF }, + { "m2v", DEMUXER_TYPE_LAVF }, + { "avi", DEMUXER_TYPE_LAVF }, + { "asx", DEMUXER_TYPE_LAVF }, + { "asf", DEMUXER_TYPE_LAVF }, + { "wmv", DEMUXER_TYPE_LAVF }, + { "wma", DEMUXER_TYPE_LAVF }, { "rm", DEMUXER_TYPE_LAVF }, { "rmvb", DEMUXER_TYPE_LAVF }, { "ra", DEMUXER_TYPE_LAVF }, - { "y4m", DEMUXER_TYPE_Y4M }, + { "y4m", DEMUXER_TYPE_LAVF }, { "mp3", DEMUXER_TYPE_LAVF }, { "wav", DEMUXER_TYPE_LAVF }, { "flac", DEMUXER_TYPE_LAVF }, @@ -63,12 +63,9 @@ static struct { { "it", DEMUXER_TYPE_LAVF }, { "mid", DEMUXER_TYPE_LAVF }, { "midi", DEMUXER_TYPE_LAVF }, - { "nsv", DEMUXER_TYPE_NSV }, - { "nsa", DEMUXER_TYPE_NSV }, - { "mpc", DEMUXER_TYPE_MPC }, -#ifdef CONFIG_WIN32DLL - { "avs", DEMUXER_TYPE_AVS }, -#endif + { "nsv", DEMUXER_TYPE_LAVF }, + { "nsa", DEMUXER_TYPE_LAVF }, + { "mpc", DEMUXER_TYPE_LAVF }, { "302", DEMUXER_TYPE_LAVF }, { "264", DEMUXER_TYPE_LAVF }, { "26l", DEMUXER_TYPE_LAVF }, diff --git a/demux/mp3_hdr.c b/demux/mp3_hdr.c deleted file mode 100644 index 27a02368da..0000000000 --- a/demux/mp3_hdr.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdio.h> - -#include "config.h" -#include "mp3_hdr.h" -#include "core/mp_msg.h" - -//----------------------- mp3 audio frame header parser ----------------------- - -static int tabsel_123[2][3][16] = { - { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, - {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, - {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0} }, - - { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0}, - {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0}, - {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0} } -}; - -static long freqs[9] = { 44100, 48000, 32000, // MPEG 1.0 - 22050, 24000, 16000, // MPEG 2.0 - 11025, 12000, 8000}; // MPEG 2.5 - -/* - * return frame size or -1 (bad frame) - */ -int mp_get_mp3_header(unsigned char* hbuf,int* chans, int* srate, int* spf, int* mpa_layer, int* br){ - int stereo,ssize,lsf,framesize,padding,bitrate_index,sampling_frequency, divisor; - int bitrate; - int layer, mult[3] = { 12000, 144000, 144000 }; - unsigned long newhead = - hbuf[0] << 24 | - hbuf[1] << 16 | - hbuf[2] << 8 | - hbuf[3]; - -// printf("head=0x%08X\n",newhead); - - // head_check: - if( (newhead & 0xffe00000) != 0xffe00000 ){ - mp_msg(MSGT_DEMUXER,MSGL_DBG2,"head_check failed\n"); - return -1; - } - - layer = 4-((newhead>>17)&3); - if(layer==4){ - mp_msg(MSGT_DEMUXER,MSGL_DBG2,"not layer-1/2/3\n"); - return -1; - } - - sampling_frequency = ((newhead>>10)&0x3); // valid: 0..2 - if(sampling_frequency==3){ - mp_msg(MSGT_DEMUXER,MSGL_DBG2,"invalid sampling_frequency\n"); - return -1; - } - - if( newhead & ((long)1<<20) ) { - // MPEG 1.0 (lsf==0) or MPEG 2.0 (lsf==1) - lsf = (newhead & ((long)1<<19)) ? 0x0 : 0x1; - sampling_frequency += (lsf*3); - } else { - // MPEG 2.5 - lsf = 1; - sampling_frequency += 6; - } - -// crc = ((newhead>>16)&0x1)^0x1; - bitrate_index = ((newhead>>12)&0xf); // valid: 1..14 - padding = ((newhead>>9)&0x1); -// fr->extension = ((newhead>>8)&0x1); -// fr->mode = ((newhead>>6)&0x3); -// fr->mode_ext = ((newhead>>4)&0x3); -// fr->copyright = ((newhead>>3)&0x1); -// fr->original = ((newhead>>2)&0x1); -// fr->emphasis = newhead & 0x3; - - stereo = ( (((newhead>>6)&0x3)) == 3) ? 1 : 2; - -// !checked later through tabsel_123[]! -// if(!bitrate_index || bitrate_index==15){ -// mp_msg(MSGT_DEMUXER,MSGL_DBG2,"Free format not supported.\n"); -// return -1; -// } - - if(lsf) - ssize = (stereo == 1) ? 9 : 17; - else - ssize = (stereo == 1) ? 17 : 32; - if(!((newhead>>16)&0x1)) ssize += 2; // CRC - - bitrate = tabsel_123[lsf][layer-1][bitrate_index]; - framesize = bitrate * mult[layer-1]; - - mp_msg(MSGT_DEMUXER,MSGL_DBG2,"FRAMESIZE: %d, layer: %d, bitrate: %d, mult: %d\n", - framesize, layer, tabsel_123[lsf][layer-1][bitrate_index], mult[layer-1]); - if(!framesize){ - mp_msg(MSGT_DEMUXER,MSGL_DBG2,"invalid framesize/bitrate_index\n"); - return -1; - } - - divisor = (layer == 3 ? (freqs[sampling_frequency] << lsf) : freqs[sampling_frequency]); - framesize /= divisor; - if(layer==1) - framesize = (framesize+padding)*4; - else - framesize += padding; - -// if(framesize<=0 || framesize>MAXFRAMESIZE) return FALSE; - if(srate) { - *srate = freqs[sampling_frequency]; - if(spf) { - if(layer == 1) - *spf = 384; - else if(layer == 2) - *spf = 1152; - else if(*srate < 32000) - *spf = 576; - else - *spf = 1152; - } - } - if(mpa_layer) *mpa_layer = layer; - if(chans) *chans = stereo; - if(br) *br = bitrate; - - return framesize; -} diff --git a/demux/mp3_hdr.h b/demux/mp3_hdr.h deleted file mode 100644 index a9b34ac12c..0000000000 --- a/demux/mp3_hdr.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_MP3_HDR_H -#define MPLAYER_MP3_HDR_H - -#include <stddef.h> - -int mp_get_mp3_header(unsigned char* hbuf,int* chans, int* freq, int* spf, int* mpa_layer, int* br); - -#define mp_decode_mp3_header(hbuf) mp_get_mp3_header(hbuf,NULL,NULL,NULL,NULL,NULL) - -static inline int mp_check_mp3_header(unsigned int head){ - unsigned char tmp[4] = {head >> 24, head >> 16, head >> 8, head}; - if( (head & 0xffe00000) != 0xffe00000 || - (head & 0x00000c00) == 0x00000c00) return 0; - if(mp_decode_mp3_header(tmp)<=0) return 0; - return 1; -} - -#endif /* MPLAYER_MP3_HDR_H */ diff --git a/demux/mpeg_hdr.c b/demux/mpeg_hdr.c deleted file mode 100644 index fcc4a33ecc..0000000000 --- a/demux/mpeg_hdr.c +++ /dev/null @@ -1,539 +0,0 @@ -/* - * based on libmpeg2/header.c by Aaron Holtzman <aholtzma@ess.engr.uvic.ca> - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "config.h" -#include "mpeg_hdr.h" -#include "libavutil/attributes.h" -#include "core/mp_msg.h" - -static float frameratecode2framerate[16] = { - 0, - // Official mpeg1/2 framerates: (1-8) - 24000.0/1001, 24,25, - 30000.0/1001, 30,50, - 60000.0/1001, 60, - // Xing's 15fps: (9) - 15, - // libmpeg3's "Unofficial economy rates": (10-13) - 5,10,12,15, - // some invalid ones: (14-15) - 0,0 -}; - - -int mp_header_process_sequence_header (mp_mpeg_header_t * picture, const unsigned char * buffer) -{ - int height; - - if ((buffer[6] & 0x20) != 0x20){ - fprintf(stderr, "missing marker bit!\n"); - return 1; /* missing marker_bit */ - } - - height = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2]; - - picture->display_picture_width = height >> 12; - picture->display_picture_height = height & 0xfff; - - picture->aspect_ratio_information = buffer[3] >> 4; - picture->frame_rate_code = buffer[3] & 15; - picture->fps=frameratecode2framerate[picture->frame_rate_code]; - picture->bitrate = (buffer[4]<<10)|(buffer[5]<<2)|(buffer[6]>>6); - picture->mpeg1 = 1; - picture->picture_structure = 3; //FRAME_PICTURE; - picture->display_time=100; - picture->frame_rate_extension_n = 1; - picture->frame_rate_extension_d = 1; - return 0; -} - -static int header_process_sequence_extension (mp_mpeg_header_t * picture, - unsigned char * buffer) -{ - /* check chroma format, size extensions, marker bit */ - - if ( ((buffer[1] & 0x06) == 0x00) || - ((buffer[1] & 0x01) != 0x00) || (buffer[2] & 0xe0) || - ((buffer[3] & 0x01) != 0x01) ) - return 1; - - picture->progressive_sequence = (buffer[1] >> 3) & 1; - picture->frame_rate_extension_n = ((buffer[5] >> 5) & 3) + 1; - picture->frame_rate_extension_d = (buffer[5] & 0x1f) + 1; - - picture->mpeg1 = 0; - return 0; -} - -static int header_process_picture_coding_extension (mp_mpeg_header_t * picture, unsigned char * buffer) -{ - picture->picture_structure = buffer[2] & 3; - picture->top_field_first = buffer[3] >> 7; - picture->repeat_first_field = (buffer[3] >> 1) & 1; - picture->progressive_frame = buffer[4] >> 7; - - // repeat_first implementation by A'rpi/ESP-team, based on libmpeg3: - picture->display_time=100; - if(picture->repeat_first_field){ - if(picture->progressive_sequence){ - if(picture->top_field_first) - picture->display_time+=200; - else - picture->display_time+=100; - } else - if(picture->progressive_frame){ - picture->display_time+=50; - } - } - //temopral hack. We calc time on every field, so if we have 2 fields - // interlaced we'll end with double time for 1 frame - if( picture->picture_structure!=3 ) picture->display_time/=2; - return 0; -} - -int mp_header_process_extension (mp_mpeg_header_t * picture, unsigned char * buffer) -{ - switch (buffer[0] & 0xf0) { - case 0x10: /* sequence extension */ - return header_process_sequence_extension (picture, buffer); - case 0x80: /* picture coding extension */ - return header_process_picture_coding_extension (picture, buffer); - } - return 0; -} - -float mpeg12_aspect_info(mp_mpeg_header_t *picture) -{ - float aspect = 0.0; - - switch(picture->aspect_ratio_information) { - case 2: // PAL/NTSC SVCD/DVD 4:3 - case 8: // PAL VCD 4:3 - case 12: // NTSC VCD 4:3 - aspect=4.0/3.0; - break; - case 3: // PAL/NTSC Widescreen SVCD/DVD 16:9 - case 6: // (PAL?)/NTSC Widescreen SVCD 16:9 - aspect=16.0/9.0; - break; - case 4: // according to ISO-138182-2 Table 6.3 - aspect=2.21; - break; - case 1: // VGA 1:1 - do not prescale - case 9: // Movie Type ??? / 640x480 - aspect=0.0; - break; - default: - mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Detected unknown aspect_ratio_information in mpeg sequence header.\n" - "Please report the aspect value (%i) along with the movie type (VGA,PAL,NTSC," - "SECAM) and the movie resolution (720x576,352x240,480x480,...) to the MPlayer" - " developers, so that we can add support for it!\nAssuming 1:1 aspect for now.\n", - picture->aspect_ratio_information); - } - - return aspect; -} - -//MPEG4 HEADERS -unsigned char mp_getbits(unsigned char *buffer, unsigned int from, unsigned char len) -{ - unsigned int n; - unsigned char m, u, l, y; - - n = from / 8; - m = from % 8; - u = 8 - m; - l = (len > u ? len - u : 0); - - y = (buffer[n] << m); - if(8 > len) - y >>= (8-len); - if(l) - y |= (buffer[n+1] >> (8-l)); - - //fprintf(stderr, "GETBITS(%d -> %d): bytes=0x%x 0x%x, n=%d, m=%d, l=%d, u=%d, Y=%d\n", - // from, (int) len, (int) buffer[n],(int) buffer[n+1], n, (int) m, (int) l, (int) u, (int) y); - return y; -} - -static inline unsigned int mp_getbits16(unsigned char *buffer, unsigned int from, unsigned char len) -{ - if(len > 8) - return (mp_getbits(buffer, from, len - 8) << 8) | mp_getbits(buffer, from + len - 8, 8); - else - return mp_getbits(buffer, from, len); -} - -#define getbits mp_getbits -#define getbits16 mp_getbits16 - -static int read_timeinc(mp_mpeg_header_t * picture, unsigned char * buffer, int n) -{ - if(picture->timeinc_bits > 8) { - picture->timeinc_unit = getbits(buffer, n, picture->timeinc_bits - 8) << 8; - n += picture->timeinc_bits - 8; - picture->timeinc_unit |= getbits(buffer, n, 8); - n += 8; - } else { - picture->timeinc_unit = getbits(buffer, n, picture->timeinc_bits); - n += picture->timeinc_bits; - } - //fprintf(stderr, "TIMEINC2: %d, bits: %d\n", picture->timeinc_unit, picture->timeinc_bits); - return n; -} - -int mp4_header_process_vol(mp_mpeg_header_t * picture, unsigned char * buffer) -{ - unsigned int n, aspect=0, aspectw av_unused=0, aspecth av_unused=0, x=1, v; - - //begins with 0x0000012x - picture->fps = 0; - picture->timeinc_bits = picture->timeinc_resolution = picture->timeinc_unit = 0; - n = 9; - if(getbits(buffer, n, 1)) - n += 7; - n++; - aspect=getbits(buffer, n, 4); - n += 4; - if(aspect == 0x0f) { - aspectw = getbits(buffer, n, 8); - n += 8; - aspecth = getbits(buffer, n, 8); - n += 8; - } - - if(getbits(buffer, n, 1)) { - n += 4; - if(getbits(buffer, n, 1)) - n += 79; - n++; - } else n++; - - n+=3; - - picture->timeinc_resolution = getbits(buffer, n, 8) << 8; - n += 8; - picture->timeinc_resolution |= getbits(buffer, n, 8); - n += 8; - - picture->timeinc_bits = 0; - v = picture->timeinc_resolution - 1; - while(v && (x<16)) { - v>>=1; - picture->timeinc_bits++; - } - picture->timeinc_bits = (picture->timeinc_bits > 1 ? picture->timeinc_bits : 1); - - n++; //marker bit - - if(getbits(buffer, n++, 1)) { //fixed_vop_timeinc - n += read_timeinc(picture, buffer, n); - - if(picture->timeinc_unit) - picture->fps = (float) picture->timeinc_resolution / (float) picture->timeinc_unit; - } - - n++; //marker bit - picture->display_picture_width = getbits16(buffer, n, 13); - n += 13; - n++; //marker bit - picture->display_picture_height = getbits16(buffer, n, 13); - n += 13; - - //fprintf(stderr, "ASPECT: %d, PARW=%d, PARH=%d, TIMEINCRESOLUTION: %d, FIXED_TIMEINC: %d (number of bits: %d), FPS: %u\n", - // aspect, aspectw, aspecth, picture->timeinc_resolution, picture->timeinc_unit, picture->timeinc_bits, picture->fps); - - return 0; -} - -void mp4_header_process_vop(mp_mpeg_header_t * picture, unsigned char * buffer) -{ - int n; - n = 0; - picture->picture_type = getbits(buffer, n, 2); - n += 2; - while(getbits(buffer, n, 1)) - n++; - n++; - getbits(buffer, n, 1); - n++; - n += read_timeinc(picture, buffer, n); -} - -#define min(a, b) ((a) <= (b) ? (a) : (b)) - -static unsigned int read_golomb(unsigned char *buffer, unsigned int *init) -{ - unsigned int x, v = 0, v2 = 0, m, len = 0, n = *init; - - while(getbits(buffer, n++, 1) == 0) - len++; - - x = len + n; - while(n < x) - { - m = min(x - n, 8); - v |= getbits(buffer, n, m); - n += m; - if(x - n > 8) - v <<= 8; - } - - v2 = 1; - for(n = 0; n < len; n++) - v2 <<= 1; - v2 = (v2 - 1) + v; - - //fprintf(stderr, "READ_GOLOMB(%u), V=2^%u + %u-1 = %u\n", *init, len, v, v2); - *init = x; - return v2; -} - -inline static int read_golomb_s(unsigned char *buffer, unsigned int *init) -{ - unsigned int v = read_golomb(buffer, init); - return (v & 1) ? ((v + 1) >> 1) : -(v >> 1); -} - -static int h264_parse_vui(mp_mpeg_header_t * picture, unsigned char * buf, unsigned int n) -{ - unsigned int overscan, vsp_color, chroma, timing, fixed_fps; - - if(getbits(buf, n++, 1)) - { - picture->aspect_ratio_information = getbits(buf, n, 8); - n += 8; - if(picture->aspect_ratio_information == 255) - { - picture->display_picture_width = (getbits(buf, n, 8) << 8) | getbits(buf, n + 8, 8); - n += 16; - - picture->display_picture_height = (getbits(buf, n, 8) << 8) | getbits(buf, n + 8, 8); - n += 16; - } - } - - if((overscan=getbits(buf, n++, 1))) - n++; - if((vsp_color=getbits(buf, n++, 1))) - { - n += 4; - if(getbits(buf, n++, 1)) - n += 24; - } - if((chroma=getbits(buf, n++, 1))) - { - read_golomb(buf, &n); - read_golomb(buf, &n); - } - if((timing=getbits(buf, n++, 1))) - { - picture->timeinc_unit = (getbits(buf, n, 8) << 24) | (getbits(buf, n+8, 8) << 16) | (getbits(buf, n+16, 8) << 8) | getbits(buf, n+24, 8); - n += 32; - - picture->timeinc_resolution = (getbits(buf, n, 8) << 24) | (getbits(buf, n+8, 8) << 16) | (getbits(buf, n+16, 8) << 8) | getbits(buf, n+24, 8); - n += 32; - - fixed_fps = getbits(buf, n, 1); - - if(picture->timeinc_unit > 0 && picture->timeinc_resolution > 0) - picture->fps = (float) picture->timeinc_resolution / (float) picture->timeinc_unit; - if(fixed_fps) - picture->fps /= 2; - } - - //fprintf(stderr, "H264_PARSE_VUI, OVESCAN=%u, VSP_COLOR=%u, CHROMA=%u, TIMING=%u, DISPW=%u, DISPH=%u, TIMERES=%u, TIMEINC=%u, FIXED_FPS=%u\n", overscan, vsp_color, chroma, timing, picture->display_picture_width, picture->display_picture_height, - // picture->timeinc_resolution, picture->timeinc_unit, picture->timeinc_unit, fixed_fps); - - return n; -} - -static int mp_unescape03(unsigned char *buf, int len) -{ - unsigned char *dest; - int i, j, skip; - - dest = malloc(len); - if(! dest) - return 0; - - j = i = skip = 0; - while(i <= len-3) - { - if(buf[i] == 0 && buf[i+1] == 0 && buf[i+2] == 3) - { - dest[j] = dest[j+1] = 0; - j += 2; - i += 3; - skip++; - } - else - { - dest[j] = buf[i]; - j++; - i++; - } - } - dest[j] = buf[len-2]; - dest[j+1] = buf[len-1]; - len -= skip; - memcpy(buf, dest, len); - free(dest); - - return len; -} - -int h264_parse_sps(mp_mpeg_header_t * picture, unsigned char * buf, int len) -{ - unsigned int n = 0, v, i, k, mbh; - int frame_mbs_only; - - len = mp_unescape03(buf, len); - - picture->fps = picture->timeinc_unit = picture->timeinc_resolution = 0; - n = 24; - read_golomb(buf, &n); - if(buf[0] >= 100){ - if(read_golomb(buf, &n) == 3) - n++; - read_golomb(buf, &n); - read_golomb(buf, &n); - n++; - if(getbits(buf, n++, 1)){ - for(i = 0; i < 8; i++) - { // scaling list is skipped for now - if(getbits(buf, n++, 1)) - { - v = 8; - for(k = (i < 6 ? 16 : 64); k && v; k--) - v = (v + read_golomb_s(buf, &n)) & 255; - } - } - } - } - read_golomb(buf, &n); - v = read_golomb(buf, &n); - if(v == 0) - read_golomb(buf, &n); - else if(v == 1) - { - getbits(buf, n++, 1); - read_golomb(buf, &n); - read_golomb(buf, &n); - v = read_golomb(buf, &n); - for(i = 0; i < v; i++) - read_golomb(buf, &n); - } - read_golomb(buf, &n); - getbits(buf, n++, 1); - picture->display_picture_width = 16 *(read_golomb(buf, &n)+1); - mbh = read_golomb(buf, &n)+1; - frame_mbs_only = getbits(buf, n++, 1); - picture->display_picture_height = 16 * (2 - frame_mbs_only) * mbh; - if(!frame_mbs_only) - getbits(buf, n++, 1); - getbits(buf, n++, 1); - if(getbits(buf, n++, 1)) - { - read_golomb(buf, &n); - read_golomb(buf, &n); - read_golomb(buf, &n); - read_golomb(buf, &n); - } - if(getbits(buf, n++, 1)) - n = h264_parse_vui(picture, buf, n); - - return n; -} - -int mp_vc1_decode_sequence_header(mp_mpeg_header_t * picture, unsigned char * buf, int len) -{ - int n, x; - - len = mp_unescape03(buf, len); - - picture->display_picture_width = picture->display_picture_height = 0; - picture->fps = 0; - n = 0; - x = getbits(buf, n, 2); - n += 2; - if(x != 3) //not advanced profile - return 0; - - getbits16(buf, n, 14); - n += 14; - picture->display_picture_width = getbits16(buf, n, 12) * 2 + 2; - n += 12; - picture->display_picture_height = getbits16(buf, n, 12) * 2 + 2; - n += 12; - getbits(buf, n, 6); - n += 6; - x = getbits(buf, n, 1); - n += 1; - if(x) //display info - { - getbits16(buf, n, 14); - n += 14; - getbits16(buf, n, 14); - n += 14; - if(getbits(buf, n++, 1)) //aspect ratio - { - x = getbits(buf, n, 4); - n += 4; - if(x == 15) - { - getbits16(buf, n, 16); - n += 16; - } - } - - if(getbits(buf, n++, 1)) //framerates - { - int frexp=0, frnum=0, frden=0; - - if(getbits(buf, n++, 1)) - { - frexp = getbits16(buf, n, 16); - n += 16; - picture->fps = (double) (frexp+1) / 32.0; - } - else - { - float frates[] = {0, 24000, 25000, 30000, 50000, 60000, 48000, 72000, 0}; - float frdivs[] = {0, 1000, 1001, 0}; - - frnum = getbits(buf, n, 8); - n += 8; - frden = getbits(buf, n, 4); - n += 4; - if((frden == 1 || frden == 2) && (frnum < 8)) - picture->fps = frates[frnum] / frdivs[frden]; - } - } - } - - //free(dest); - return 1; -} diff --git a/demux/mpeg_hdr.h b/demux/mpeg_hdr.h deleted file mode 100644 index ccd84bcdb0..0000000000 --- a/demux/mpeg_hdr.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_MPEG_HDR_H -#define MPLAYER_MPEG_HDR_H - -typedef struct { - // video info: - int mpeg1; // 0=mpeg2 1=mpeg1 - int display_picture_width; - int display_picture_height; - int aspect_ratio_information; - int frame_rate_code; - float fps; - int frame_rate_extension_n; - int frame_rate_extension_d; - int bitrate; // 0x3FFFF==VBR - // timing: - int picture_structure; - int progressive_sequence; - int repeat_first_field; - int progressive_frame; - int top_field_first; - int display_time; // secs*100 - //the following are for mpeg4 - unsigned int timeinc_resolution, timeinc_bits, timeinc_unit; - int picture_type; -} mp_mpeg_header_t; - -int mp_header_process_sequence_header (mp_mpeg_header_t * picture, const unsigned char * buffer); -int mp_header_process_extension (mp_mpeg_header_t * picture, unsigned char * buffer); -float mpeg12_aspect_info(mp_mpeg_header_t *picture); -int mp4_header_process_vol(mp_mpeg_header_t * picture, unsigned char * buffer); -void mp4_header_process_vop(mp_mpeg_header_t * picture, unsigned char * buffer); -int h264_parse_sps(mp_mpeg_header_t * picture, unsigned char * buf, int len); -int mp_vc1_decode_sequence_header(mp_mpeg_header_t * picture, unsigned char * buf, int len); - -unsigned char mp_getbits(unsigned char *buffer, unsigned int from, unsigned char len); - -#endif /* MPLAYER_MPEG_HDR_H */ diff --git a/demux/ms_hdr.h b/demux/ms_hdr.h index 8e545635dd..7f837a58a4 100644 --- a/demux/ms_hdr.h +++ b/demux/ms_hdr.h @@ -22,6 +22,14 @@ #include <sys/types.h> #include "config.h" +#include "compat/mpbswap.h" + +#ifndef mmioFOURCC +#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \ + ( (uint32_t)(uint8_t)(ch0) | ( (uint32_t)(uint8_t)(ch1) << 8 ) | \ + ( (uint32_t)(uint8_t)(ch2) << 16 ) | ( (uint32_t)(uint8_t)(ch3) << 24 ) ) +#endif + #ifndef _WAVEFORMATEX_ #define _WAVEFORMATEX_ typedef struct __attribute__((__packed__)) _WAVEFORMATEX { diff --git a/demux/parse_es.c b/demux/parse_es.c deleted file mode 100644 index 8e43446c1f..0000000000 --- a/demux/parse_es.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * MPEG-ES video parser - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include "config.h" -#include "core/mp_msg.h" - -#include "stream/stream.h" -#include "demux.h" -#include "parse_es.h" - -//static unsigned char videobuffer[MAX_VIDEO_PACKET_SIZE]; -unsigned char* videobuffer=NULL; -int videobuf_len=0; -int next_nal = -1; -///! legacy variable, 4 if stream is synced, 0 if not -int videobuf_code_len=0; - -#define MAX_SYNCLEN (10 * 1024 * 1024) -// sync video stream, and returns next packet code -int sync_video_packet(demux_stream_t *ds){ - if (!videobuf_code_len) { - int skipped=0; - if (!demux_pattern_3(ds, NULL, MAX_SYNCLEN, &skipped, 0x100)) { - if (skipped == MAX_SYNCLEN) - mp_msg(MSGT_DEMUXER, MSGL_ERR, "parse_es: could not sync video stream!\n"); - goto eof_out; - } - next_nal = demux_getc(ds); - if (next_nal < 0) - goto eof_out; - videobuf_code_len = 4; - if(skipped) mp_dbg(MSGT_PARSEES,MSGL_DBG2,"videobuf: %d bytes skipped (next: 0x1%02X)\n",skipped,next_nal); - } - return 0x100|next_nal; - -eof_out: - next_nal = -1; - videobuf_code_len = 0; - return 0; -} - -// return: packet length -int read_video_packet(demux_stream_t *ds){ -int packet_start; - int res, read; - - if (VIDEOBUFFER_SIZE - videobuf_len < 5) - return 0; - // SYNC STREAM -// if(!sync_video_packet(ds)) return 0; // cannot sync (EOF) - - // COPY STARTCODE: - packet_start=videobuf_len; - videobuffer[videobuf_len+0]=0; - videobuffer[videobuf_len+1]=0; - videobuffer[videobuf_len+2]=1; - videobuffer[videobuf_len+3]=next_nal; - videobuf_len+=4; - - // READ PACKET: - res = demux_pattern_3(ds, &videobuffer[videobuf_len], - VIDEOBUFFER_SIZE - videobuf_len, &read, 0x100); - videobuf_len += read; - if (!res) - goto eof_out; - - videobuf_len-=3; - - 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: - next_nal = demux_getc(ds); - if (next_nal < 0) - goto eof_out; - videobuf_code_len=4; - - return videobuf_len-packet_start; - -eof_out: - next_nal = -1; - videobuf_code_len = 0; - 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); -} - -/* stripped down version of a52_syncinfo() from liba52 - * copyright belongs to Michel Lespinasse <walken@zoy.org> - * and Aaron Holtzman <aholtzma@ess.engr.uvic.ca> */ -int mp_a52_framesize(uint8_t * buf, int *srate) -{ - int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112, - 128, 160, 192, 224, 256, 320, 384, 448, - 512, 576, 640 - }; - uint8_t halfrate[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 }; - int frmsizecod, bitrate, half; - - if ((buf[0] != 0x0b) || (buf[1] != 0x77)) /* syncword */ - return 0; - - if (buf[5] >= 0x60) /* bsid >= 12 */ - return 0; - - half = halfrate[buf[5] >> 3]; - - frmsizecod = buf[4] & 63; - if (frmsizecod >= 38) - return 0; - - bitrate = rate[frmsizecod >> 1]; - - switch (buf[4] & 0xc0) { - case 0: /* 48 KHz */ - *srate = 48000 >> half; - return 4 * bitrate; - case 0x40: /* 44.1 KHz */ - *srate = 44100 >> half; - return 2 * (320 * bitrate / 147 + (frmsizecod & 1)); - case 0x80: /* 32 KHz */ - *srate = 32000 >> half; - return 6 * bitrate; - } - - return 0; -} diff --git a/demux/parse_es.h b/demux/parse_es.h deleted file mode 100644 index af558e379d..0000000000 --- a/demux/parse_es.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_PARSE_ES_H -#define MPLAYER_PARSE_ES_H - -#include <stdint.h> - -#include "demux.h" - -#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); - -int mp_a52_framesize(uint8_t *buf, int *srate); - -#endif /* MPLAYER_PARSE_ES_H */ diff --git a/demux/stheader.h b/demux/stheader.h index ff98430a65..475d063637 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -24,7 +24,6 @@ #include "codec_tags.h" #include "audio/chmap.h" -#include "aviheader.h" #include "ms_hdr.h" struct MPOpts; struct demuxer; @@ -113,7 +112,6 @@ typedef struct sh_audio { struct af_stream *afilter; // the audio filter stream const struct ad_functions *ad_driver; // win32-compatible codec parameters: - AVIStreamHeader audio; WAVEFORMATEX *wf; // note codec extradata may be either under "wf" or "codecdata" unsigned char *codecdata; @@ -153,7 +151,6 @@ typedef struct sh_video { const struct vd_functions *vd_driver; int vf_initialized; // -1 failed, 0 not done, 1 done // win32-compatible codec parameters: - AVIStreamHeader video; BITMAPINFOHEADER *bih; } sh_video_t; @@ -173,9 +170,6 @@ struct sh_audio *new_sh_audio_aid(struct demuxer *demuxer, int id, int aid); #define new_sh_video(d, i) new_sh_video_vid(d, i, i) struct sh_video *new_sh_video_vid(struct demuxer *demuxer, int id, int vid); #define new_sh_sub(d, i) new_sh_sub_sid(d, i, i) -struct sh_sub *new_sh_sub_sid(struct demuxer *demuxer, int id, int sid); -struct sh_sub *new_sh_sub_sid_lang(struct demuxer *demuxer, int id, int sid, - const char *lang); struct sh_stream *new_sh_stream(struct demuxer *demuxer, enum stream_type type); // video.c: diff --git a/demux/video.c b/demux/video.c index 69749e03d1..48154905fe 100644 --- a/demux/video.c +++ b/demux/video.c @@ -32,530 +32,23 @@ #include "stream/stream.h" #include "demux.h" #include "stheader.h" -#include "parse_es.h" -#include "mpeg_hdr.h" - -/* sub_cc (closed captions)*/ -//#include "sub/sub_cc.h" - -/* biCompression constant */ -#define BI_RGB 0L - -static mp_mpeg_header_t picture; - -static int telecine=0; -static float telecine_cnt=-2.5; - -typedef enum { - VIDEO_MPEG12, - VIDEO_MPEG4, - VIDEO_H264, - VIDEO_VC1, - VIDEO_OTHER -} video_codec_t; - -static video_codec_t find_video_codec(sh_video_t *sh_video) -{ - demux_stream_t *d_video=sh_video->ds; - int fmt = d_video->demuxer->file_format; - - if( - (fmt == DEMUXER_TYPE_MPEG_ES) || - (fmt == DEMUXER_TYPE_MPEG_GXF) || - (fmt == DEMUXER_TYPE_MPEG_PES) || - ( - (fmt == DEMUXER_TYPE_MPEG_PS || fmt == DEMUXER_TYPE_MPEG_TS) && - ((! sh_video->format) || (sh_video->format==0x10000001) || (sh_video->format==0x10000002)) - ) - ) - return VIDEO_MPEG12; - else if((fmt == DEMUXER_TYPE_MPEG4_ES) || - ((fmt == DEMUXER_TYPE_MPEG_TS) && (sh_video->format==0x10000004)) || - ((fmt == DEMUXER_TYPE_MPEG_PS) && (sh_video->format==0x10000004)) - ) - return VIDEO_MPEG4; - else if((fmt == DEMUXER_TYPE_H264_ES) || - ((fmt == DEMUXER_TYPE_MPEG_TS) && (sh_video->format==0x10000005)) || - ((fmt == DEMUXER_TYPE_MPEG_PS) && (sh_video->format==0x10000005)) - ) - return VIDEO_H264; - else if((fmt == DEMUXER_TYPE_MPEG_PS || fmt == DEMUXER_TYPE_MPEG_TS) && - (sh_video->format==mmioFOURCC('W', 'V', 'C', '1'))) - return VIDEO_VC1; - else if (fmt == DEMUXER_TYPE_ASF && sh_video->bih && sh_video->bih->biCompression == mmioFOURCC('D', 'V', 'R', ' ')) - return VIDEO_MPEG12; - else - return VIDEO_OTHER; -} int video_read_properties(sh_video_t *sh_video){ -demux_stream_t *d_video=sh_video->ds; -video_codec_t video_codec = find_video_codec(sh_video); -// Determine image properties: -switch(video_codec){ - case VIDEO_OTHER: { - if((d_video->demuxer->file_format == DEMUXER_TYPE_ASF) || (d_video->demuxer->file_format == DEMUXER_TYPE_AVI)) { - // display info: - // in case no strf chunk has been seen in avi, we have no bitmap header - if(!sh_video->bih) return 0; - sh_video->format=sh_video->bih->biCompression; - mp_set_video_codec_from_tag(sh_video); - sh_video->disp_w=sh_video->bih->biWidth; - sh_video->disp_h=abs(sh_video->bih->biHeight); - } - break; - } - case VIDEO_MPEG4: { - int pos = 0, vop_cnt=0, units[3]; - videobuf_len=0; videobuf_code_len=0; - mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for Video Object Start code... "); - while(1){ - int i=sync_video_packet(d_video); - if(i<=0x11F) break; // found it! - if(!i || !skip_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n"); - return 0; - } - } - mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n"); - if(!videobuffer) { - videobuffer = av_malloc(VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE); - if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE); - else { - mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n"); - return 0; - } - } - mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for Video Object Layer Start code... "); - while(1){ - int i=sync_video_packet(d_video); - mp_msg(MSGT_DECVIDEO,MSGL_V,"M4V: 0x%X\n",i); - if(i>=0x120 && i<=0x12F) break; // found it! - if(!i || !read_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n"); - return 0; - } - } - pos = videobuf_len+4; - if(!read_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read Video Object Layer Header\n"); - return 0; - } - mp4_header_process_vol(&picture, &(videobuffer[pos])); - mp_msg(MSGT_DECVIDEO,MSGL_V,"OK! FPS SEEMS TO BE %.3f\nSearching for Video Object Plane Start code... ", sh_video->fps); - mp4_init: - while(1){ - int i=sync_video_packet(d_video); - if(i==0x1B6) break; // found it! - if(!i || !read_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n"); - return 0; - } - } - pos = videobuf_len+4; - if(!read_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read Video Object Plane Header\n"); - return 0; - } - mp4_header_process_vop(&picture, &(videobuffer[pos])); - sh_video->disp_w = picture.display_picture_width; - sh_video->disp_h = picture.display_picture_height; - units[vop_cnt] = picture.timeinc_unit; - vop_cnt++; - //mp_msg(MSGT_DECVIDEO,MSGL_V, "TYPE: %d, unit: %d\n", picture.picture_type, picture.timeinc_unit); - if(!picture.fps) { - int i, mn, md, mx, diff; - if(vop_cnt < 3) - goto mp4_init; - - i=0; - mn = mx = units[0]; - for(i=0; i<3; i++) { - if(units[i] < mn) - mn = units[i]; - if(units[i] > mx) - mx = units[i]; - } - md = mn; - for(i=0; i<3; i++) { - if((units[i] > mn) && (units[i] < mx)) - md = units[i]; - } - mp_msg(MSGT_DECVIDEO,MSGL_V, "MIN: %d, mid: %d, max: %d\n", mn, md, mx); - if(mx - md > md - mn) - diff = md - mn; - else - diff = mx - md; - if(diff > 0){ - picture.fps = ((float)picture.timeinc_resolution) / diff; - mp_msg(MSGT_DECVIDEO,MSGL_V, "FPS seems to be: %f, resolution: %d, delta_units: %d\n", picture.fps, picture.timeinc_resolution, diff); - } - } - if(picture.fps) { - sh_video->fps=picture.fps; - sh_video->frametime=1.0/picture.fps; - mp_msg(MSGT_DECVIDEO,MSGL_INFO, "FPS seems to be: %f\n", picture.fps); - } - mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n"); - sh_video->format=0x10000004; - break; - } - case VIDEO_H264: { - int pos = 0; - videobuf_len=0; videobuf_code_len=0; - mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for sequence parameter set... "); - while(1){ - int i=sync_video_packet(d_video); - if((i&~0x60) == 0x107 && i != 0x107) break; // found it! - if(!i || !skip_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n"); - return 0; - } - } - mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n"); - if(!videobuffer) { - videobuffer = av_malloc(VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE); - if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE); - else { - mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n"); - return 0; - } - } - pos = videobuf_len+4; - if(!read_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read sequence parameter set\n"); - return 0; - } - h264_parse_sps(&picture, &(videobuffer[pos]), videobuf_len - pos); - sh_video->disp_w=picture.display_picture_width; - sh_video->disp_h=picture.display_picture_height; - mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for picture parameter set... "); - while(1){ - int i=sync_video_packet(d_video); - mp_msg(MSGT_DECVIDEO,MSGL_V,"H264: 0x%X\n",i); - if((i&~0x60) == 0x108 && i != 0x108) break; // found it! - if(!i || !read_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n"); - return 0; - } - } - mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\nSearching for Slice... "); - while(1){ - int i=sync_video_packet(d_video); - if((i&~0x60) == 0x101 || (i&~0x60) == 0x102 || (i&~0x60) == 0x105) break; // found it! - if(!i || !read_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n"); - return 0; - } - } - mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n"); - sh_video->format=0x10000005; - if(picture.fps) { - sh_video->fps=picture.fps; - sh_video->frametime=1.0/picture.fps; - mp_msg(MSGT_DECVIDEO,MSGL_INFO, "FPS seems to be: %f\n", picture.fps); - } - break; - } - case VIDEO_MPEG12: { - if (d_video->demuxer->file_format == DEMUXER_TYPE_ASF) { // DVR-MS - if(!sh_video->bih) return 0; - sh_video->format=sh_video->bih->biCompression; - } -mpeg_header_parser: - // Find sequence_header first: - videobuf_len=0; videobuf_code_len=0; - telecine=0; telecine_cnt=-2.5; - mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for sequence header... "); - while(1){ - int i=sync_video_packet(d_video); - if(i==0x1B3) break; // found it! - if(!i || !skip_video_packet(d_video)){ - if( mp_msg_test(MSGT_DECVIDEO,MSGL_V) ) mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n"); - mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"MPEG: FATAL: EOF while searching for sequence header.\n"); - return 0; - } - } - mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n"); - // ========= Read & process sequence header & extension ============ - if(!videobuffer) { - videobuffer = av_malloc(VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE); - if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE); - else { - mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n"); - return 0; - } - } - - if(!read_video_packet(d_video)){ - mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"FATAL: Cannot read sequence header.\n"); - return 0; - } - if(mp_header_process_sequence_header (&picture, &videobuffer[4])) { - mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"MPEG: bad sequence header\n"); - goto mpeg_header_parser; - } - if(sync_video_packet(d_video)==0x1B5){ // next packet is seq. ext. - int pos=videobuf_len; - if(!read_video_packet(d_video)){ - mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"FATAL: Cannot read sequence header extension.\n"); - return 0; - } - if(mp_header_process_extension (&picture, &videobuffer[pos+4])) { - mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"MPEG: bad sequence header extension\n"); - return 0; - } - } - - // display info: - sh_video->format=picture.mpeg1?0x10000001:0x10000002; // mpeg video - sh_video->fps=picture.fps * picture.frame_rate_extension_n / picture.frame_rate_extension_d; - if(!sh_video->fps){ - sh_video->frametime=0; - } else { - sh_video->frametime=1.0/sh_video->fps; - } - sh_video->disp_w=picture.display_picture_width; - sh_video->disp_h=picture.display_picture_height; - // bitrate: - if(picture.bitrate!=0x3FFFF) // unspecified/VBR ? - sh_video->i_bps=picture.bitrate * 400 / 8; - // info: - mp_dbg(MSGT_DECVIDEO,MSGL_DBG2,"mpeg bitrate: %d (%X)\n",picture.bitrate,picture.bitrate); - mp_msg(MSGT_DECVIDEO,MSGL_INFO,"VIDEO: %s %dx%d (aspect %d) %5.3f fps %5.1f kbps (%4.1f kbyte/s)\n", - picture.mpeg1?"MPEG1":"MPEG2", - sh_video->disp_w,sh_video->disp_h, - picture.aspect_ratio_information, - sh_video->fps, - sh_video->i_bps * 8 / 1000.0, - sh_video->i_bps / 1000.0 ); - break; - } - case VIDEO_VC1: { - // Find sequence_header: - videobuf_len=0; - videobuf_code_len=0; - mp_msg(MSGT_DECVIDEO,MSGL_INFO,"Searching for VC1 sequence header... "); - while(1){ - int i=sync_video_packet(d_video); - if(i==0x10F) break; // found it! - if(!i || !skip_video_packet(d_video)){ - if( mp_msg_test(MSGT_DECVIDEO,MSGL_V) ) mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n"); - mp_msg(MSGT_DECVIDEO,MSGL_ERR, "Couldn't find VC-1 sequence header\n"); - return 0; - } - } - mp_msg(MSGT_DECVIDEO,MSGL_INFO,"found\n"); - if(!videobuffer) { - videobuffer = av_malloc(VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE); - if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE); - else { - mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n"); - return 0; - } - } - if(!read_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_ERR, "Couldn't read VC-1 sequence header!\n"); - return 0; - } - - while(1) { - int i=sync_video_packet(d_video); - if(i==0x10E) break; // found it! - if(!i || !skip_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_V,"Couldn't find VC-1 entry point sync-code:(\n"); - return 0; - } - } - if(!read_video_packet(d_video)){ - mp_msg(MSGT_DECVIDEO,MSGL_V,"Couldn't read VC-1 entry point sync-code:(\n"); - return 0; - } - - if(mp_vc1_decode_sequence_header(&picture, &videobuffer[4], videobuf_len-4)) { - sh_video->bih = calloc(1, sizeof(*sh_video->bih) + videobuf_len); - if(sh_video->bih == NULL) { - mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Couldn't alloc %zu bytes for VC-1 extradata!\n", sizeof(*sh_video->bih) + videobuf_len); - return 0; - } - sh_video->bih->biSize= sizeof(*sh_video->bih) + videobuf_len; - memcpy(sh_video->bih + 1, videobuffer, videobuf_len); - sh_video->bih->biCompression = sh_video->format; - sh_video->bih->biWidth = sh_video->disp_w = picture.display_picture_width; - sh_video->bih->biHeight = sh_video->disp_h = picture.display_picture_height; - if(picture.fps > 0) { - sh_video->frametime=1.0/picture.fps; - sh_video->fps = picture.fps; - } - mp_msg(MSGT_DECVIDEO,MSGL_INFO,"VIDEO: VC-1 %dx%d, %5.3f fps, header len: %d\n", - sh_video->disp_w, sh_video->disp_h, sh_video->fps, videobuf_len); - } - break; - } -} // switch(file_format) -if (d_video->demuxer->file_format == DEMUXER_TYPE_MPEG_PS || - d_video->demuxer->file_format == DEMUXER_TYPE_MPEG_TS) - mp_set_video_codec_from_tag(sh_video); return 1; } -static void process_userdata(const unsigned char* buf,int len){ - int i; - /* if the user data starts with "CC", assume it is a CC info packet */ - if(len>2 && buf[0]=='C' && buf[1]=='C'){ -// mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"video.c: process_userdata() detected Closed Captions!\n"); - //subcc_process_data(buf+2,len-2); - } - if(verbose<2) return; - fprintf(stderr, "user_data: len=%3d %02X %02X %02X %02X '", - len, buf[0], buf[1], buf[2], buf[3]); - for(i=0;i<len;i++) -// if(buf[i]>=32 && buf[i]<127) fputc(buf[i], stderr); - if(buf[i]&0x60) fputc(buf[i]&0x7F, stderr); - fprintf(stderr, "'\n"); -} - int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char** start,int force_fps){ demux_stream_t *d_video=sh_video->ds; demuxer_t *demuxer=d_video->demuxer; float frame_time=1; float pts1=d_video->pts; - float pts=0; - float fps; - int picture_coding_type=0; int in_size=0; - video_codec_t video_codec = find_video_codec(sh_video); *start=NULL; - if(video_codec == VIDEO_MPEG12){ - int in_frame=0; - //float newfps; - //videobuf_len=0; - while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){ - int i=sync_video_packet(d_video); - //void* buffer=&videobuffer[videobuf_len+4]; - int start=videobuf_len+4; - if(in_frame){ - if(i<0x101 || i>=0x1B0){ // not slice code -> end of frame - if(!i) return -1; // EOF - break; - } - } else { - if(i==0x100){ - pts=d_video->pts; - d_video->pts=0; - } - if(i>=0x101 && i<0x1B0) in_frame=1; // picture startcode - else if(!i) return -1; // EOF - } - if(!read_video_packet(d_video)) return -1; // EOF - // process headers: - switch(i){ - case 0x1B3: mp_header_process_sequence_header (&picture, &videobuffer[start]);break; - case 0x1B5: mp_header_process_extension (&picture, &videobuffer[start]);break; - case 0x1B2: process_userdata (&videobuffer[start], videobuf_len-start);break; - case 0x100: picture_coding_type=(videobuffer[start+1] >> 3) & 7;break; - } - } - fps = picture.fps * picture.frame_rate_extension_n / picture.frame_rate_extension_d; - - *start=videobuffer; in_size=videobuf_len; - - // get mpeg fps: - if(sh_video->fps!=fps) if(!force_fps && !telecine){ - mp_msg(MSGT_CPLAYER,MSGL_WARN,"Warning! FPS changed %5.3f -> %5.3f (%f) [%d] \n",sh_video->fps,fps,sh_video->fps-fps,picture.frame_rate_code); - sh_video->fps=fps; - sh_video->frametime=1.0/fps; - } - - // fix mpeg2 frametime: - frame_time=(picture.display_time)*0.01f; - picture.display_time=100; - videobuf_len=0; - - telecine_cnt*=0.9; // drift out error - telecine_cnt+=frame_time-5.0/4.0; - mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"\r telecine = %3.1f %5.3f \n",frame_time,telecine_cnt); - - if(telecine){ - frame_time=1; - if(telecine_cnt<-1.5 || telecine_cnt>1.5){ - mp_tmsg(MSGT_DECVIDEO,MSGL_INFO,"\ndemux_mpg: 30000/1001fps NTSC content detected, switching framerate.\n"); - telecine=0; - } - } else - if(telecine_cnt>-0.5 && telecine_cnt<0.5 && !force_fps){ - sh_video->fps=sh_video->fps*4/5; - sh_video->frametime=sh_video->frametime*5/4; - mp_tmsg(MSGT_DECVIDEO,MSGL_INFO,"\ndemux_mpg: 24000/1001fps progressive NTSC content detected, switching framerate.\n"); - telecine=1; - } - } else if(video_codec == VIDEO_MPEG4){ - while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){ - int i=sync_video_packet(d_video); - if(!i) return -1; - if(!read_video_packet(d_video)) return -1; // EOF - if(i==0x1B6) break; - } - *start=videobuffer; in_size=videobuf_len; - videobuf_len=0; - } else if(video_codec == VIDEO_H264){ - int in_picture = 0; - while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){ - int i=sync_video_packet(d_video); - int pos = videobuf_len+4; - if(!i) return -1; - if(!read_video_packet(d_video)) return -1; // EOF - if((i&~0x60) == 0x107 && i != 0x107) { - h264_parse_sps(&picture, &(videobuffer[pos]), videobuf_len - pos); - if(picture.fps > 0) { - sh_video->fps=picture.fps; - sh_video->frametime=1.0/picture.fps; - } - i=sync_video_packet(d_video); - if(!i) return -1; - if(!read_video_packet(d_video)) return -1; // EOF - } - - // here starts the access unit end detection code - // see the mail on MPlayer-dev-eng for details: - // Date: Sat, 17 Sep 2005 11:24:06 +0200 - // Subject: Re: [MPlayer-dev-eng] [RFC] h264 ES parser problems - // Message-ID: <20050917092406.GA7699@rz.uni-karlsruhe.de> - if((i&~0x60) == 0x101 || (i&~0x60) == 0x102 || (i&~0x60) == 0x105) - // found VCL NAL with slice header i.e. start of current primary coded - // picture, so start scanning for the end now - in_picture = 1; - if (in_picture) { - i = sync_video_packet(d_video) & ~0x60; // code of next packet - if(i == 0x106 || i == 0x109) break; // SEI or access unit delim. - if(i == 0x101 || i == 0x102 || i == 0x105) { - // assuming arbitrary slice ordering is not allowed, the - // first_mb_in_slice (golomb encoded) value should be 0 then - // for the first VCL NAL in a picture - if (demux_peekc(d_video) & 0x80) - break; - } - } - } - *start=videobuffer; in_size=videobuf_len; - videobuf_len=0; - } else if(video_codec == VIDEO_VC1) { - while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE) { - int i=sync_video_packet(d_video); - if(!i) return -1; - if(!read_video_packet(d_video)) return -1; // EOF - if(i==0x10D) break; - } - *start=videobuffer; - in_size=videobuf_len; - videobuf_len=0; - } else { // frame-based file formats: (AVI,ASF,MOV) in_size=ds_get_packet(d_video,start); if(in_size<0) return -1; // EOF - } //------------------------ frame decoded. -------------------- @@ -564,14 +57,12 @@ int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char** // override frame_time for variable/unknown FPS formats: if(!force_fps) switch(demuxer->file_format){ - case DEMUXER_TYPE_GIF: case DEMUXER_TYPE_MATROSKA: case DEMUXER_TYPE_MNG: if(d_video->pts>0 && pts1>0 && d_video->pts>pts1) frame_time=d_video->pts-pts1; break; - case DEMUXER_TYPE_TV: - case DEMUXER_TYPE_ASF: { + case DEMUXER_TYPE_TV: { double next_pts = ds_get_next_pts(d_video); double d= (next_pts != MP_NOPTS_VALUE) ? next_pts - d_video->pts : d_video->pts-pts1; if(d>=0){ @@ -599,21 +90,7 @@ int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char** break; } - if(video_codec == VIDEO_MPEG12){ - sh_video->pts+=frame_time; - if(picture_coding_type==1) - d_video->keyframe = true; - if(picture_coding_type<=2 && sh_video->i_pts){ - sh_video->pts=sh_video->i_pts; - sh_video->i_pts=pts; - } else { - if(pts){ - if(picture_coding_type<=2) sh_video->i_pts=pts; - else sh_video->pts=pts; - } - } - } else - sh_video->pts=d_video->pts; + sh_video->pts=d_video->pts; if(frame_time_ptr) *frame_time_ptr=frame_time; return in_size; |