📄 demux_real.c
字号:
/* Real parser & demuxer (C) Alex Beregszaszi Based on FFmpeg's libav/rm.c.Audio codecs: (supported by RealPlayer8 for Linux) DNET - RealAudio 3.0, really it's AC3 in swapped-byteorder SIPR - SiproLab's audio codec, ACELP decoder working with MPlayer, needs fine-tuning too :) ATRC - RealAudio 8 (ATRAC3) - www.minidisc.org/atrac3_article.pdf, ACM decoder uploaded, needs some fine-tuning to work -> RealAudio 8 COOK/COKR - Real Cooker -> RealAudio G2Video codecs: (supported by RealPlayer8 for Linux) RV10 - H.263 based, working with libavcodec's decoder RV20-RV40 - using RealPlayer's codec plugins*/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include "config.h"#include "mp_msg.h"#include "help_mp.h"#include "stream.h"#include "demuxer.h"#include "stheader.h"#include "bswap.h"//#define mp_dbg(mod,lev, args... ) mp_msg_c((mod<<8)|lev, ## args )#define MKTAG(a, b, c, d) (a | (b << 8) | (c << 16) | (d << 24))#define MAX_STREAMS 32typedef struct { int timestamp; int offset;// int packetno;// int len; /* only filled by our index generator */// int flags; /* only filled by our index generator */} real_index_table_t;typedef struct { /* for seeking */ int index_chunk_offset; real_index_table_t *index_table[MAX_STREAMS]; // int *index_table[MAX_STREAMS]; int index_table_size[MAX_STREAMS]; int index_malloc_size[MAX_STREAMS]; int data_chunk_offset; int num_of_packets; int current_packet; // need for seek int audio_need_keyframe; int video_after_seek; int current_apacket; int current_vpacket; // timestamp correction: int kf_base;// timestamp of the prev. video keyframe int kf_pts; // timestamp of next video keyframe int a_pts; // previous audio timestamp float v_pts; // previous video timestamp unsigned long duration; /* stream id table */// int last_a_stream;// int a_streams[MAX_STREAMS];// int last_v_stream;// int v_streams[MAX_STREAMS]; /** * Used to demux multirate files */ int is_multirate; ///< != 0 for multirate files int str_data_offset[MAX_STREAMS]; ///< Data chunk offset for every audio/video stream int audio_curpos; ///< Current file position for audio demuxing int video_curpos; ///< Current file position for video demuxing int a_num_of_packets; ///< Number of audio packets int v_num_of_packets; ///< Number of video packets int a_idx_ptr; ///< Audio index position pointer int v_idx_ptr; ///< Video index position pointer int a_bitrate; ///< Audio bitrate int v_bitrate; ///< Video bitrate int stream_switch; ///< Flag used to switch audio/video demuxing} real_priv_t;/* originally from FFmpeg */static void get_str(int isbyte, demuxer_t *demuxer, char *buf, int buf_size){ int len; if (isbyte) len = stream_read_char(demuxer->stream); else len = stream_read_word(demuxer->stream); stream_read(demuxer->stream, buf, (len > buf_size) ? buf_size : len); if (len > buf_size) stream_skip(demuxer->stream, len-buf_size); mp_msg(MSGT_DEMUX, MSGL_V, "read_str: %d bytes read\n", len);}static void skip_str(int isbyte, demuxer_t *demuxer){ int len; if (isbyte) len = stream_read_char(demuxer->stream); else len = stream_read_word(demuxer->stream); stream_skip(demuxer->stream, len); mp_msg(MSGT_DEMUX, MSGL_V, "skip_str: %d bytes skipped\n", len);}static void dump_index(demuxer_t *demuxer, int stream_id){ real_priv_t *priv = demuxer->priv; real_index_table_t *index; int i, entries; if (verbose<=1) return; if (stream_id > MAX_STREAMS) return; index = priv->index_table[stream_id]; entries = priv->index_table_size[stream_id]; mp_msg(MSGT_DEMUX, MSGL_V, "Index table for stream %d\n", stream_id); for (i = 0; i < entries; i++) {#if 1 mp_msg(MSGT_DEMUX, MSGL_V,"i: %d, pos: %d, timestamp: %d\n", i, index[i].offset, index[i].timestamp);#else mp_msg(MSGT_DEMUX, MSGL_V,"packetno: %x pos: %x len: %x timestamp: %x flags: %x\n", index[i].packetno, index[i].offset, index[i].len, index[i].timestamp, index[i].flags);#endif }}static int parse_index_chunk(demuxer_t *demuxer){ real_priv_t *priv = demuxer->priv; int origpos = stream_tell(demuxer->stream); int next_header_pos = priv->index_chunk_offset; int i, entries, stream_id;read_index: stream_seek(demuxer->stream, next_header_pos); i = stream_read_dword_le(demuxer->stream); if ((i == -256) || (i != MKTAG('I', 'N', 'D', 'X'))) { mp_msg(MSGT_DEMUX, MSGL_WARN,"Something went wrong, no index chunk found on given address (%d)\n", next_header_pos); index_mode = -1; if (i == -256) stream_reset(demuxer->stream); stream_seek(demuxer->stream, origpos); return 0; //goto end; } mp_msg(MSGT_DEMUX, MSGL_V,"Reading index table from index chunk (%d)\n", next_header_pos); i = stream_read_dword(demuxer->stream); mp_msg(MSGT_DEMUX, MSGL_V,"size: %d bytes\n", i); i = stream_read_word(demuxer->stream); if (i != 0) mp_msg(MSGT_DEMUX, MSGL_WARN,"Hmm, index table with unknown version (%d), please report it to MPlayer developers!\n", i); entries = stream_read_dword(demuxer->stream); mp_msg(MSGT_DEMUX, MSGL_V,"entries: %d\n", entries); stream_id = stream_read_word(demuxer->stream); mp_msg(MSGT_DEMUX, MSGL_V,"stream_id: %d\n", stream_id); next_header_pos = stream_read_dword(demuxer->stream); mp_msg(MSGT_DEMUX, MSGL_V,"next_header_pos: %d\n", next_header_pos); if (entries <= 0) { if (next_header_pos) goto read_index; i = entries; goto end; } priv->index_table_size[stream_id] = entries; priv->index_table[stream_id] = malloc(priv->index_table_size[stream_id] * sizeof(real_index_table_t)); for (i = 0; i < entries; i++) { stream_skip(demuxer->stream, 2); /* version */ priv->index_table[stream_id][i].timestamp = stream_read_dword(demuxer->stream); priv->index_table[stream_id][i].offset = stream_read_dword(demuxer->stream); stream_skip(demuxer->stream, 4); /* packetno */// priv->index_table[stream_id][i].packetno = stream_read_dword(demuxer->stream);// printf("Index table: Stream#%d: entry: %d: pos: %d\n",// stream_id, i, priv->index_table[stream_id][i].offset); } dump_index(demuxer, stream_id); if (next_header_pos > 0) goto read_index;end: if (i == -256) stream_reset(demuxer->stream); stream_seek(demuxer->stream, origpos); if (i == -256) return 0; else return 1;}#if 1static void add_index_item(demuxer_t *demuxer, int stream_id, int timestamp, int offset){ if ((unsigned)stream_id < MAX_STREAMS) { real_priv_t *priv = demuxer->priv; real_index_table_t *index; if (priv->index_table_size[stream_id] >= priv->index_malloc_size[stream_id]) { if (priv->index_malloc_size[stream_id] == 0) priv->index_malloc_size[stream_id] = 2048; else priv->index_malloc_size[stream_id] += priv->index_malloc_size[stream_id] / 2; // in case we have a really large chunk... if (priv->index_table_size[stream_id] >= priv->index_malloc_size[stream_id]) priv->index_malloc_size[stream_id] = priv->index_table_size[stream_id] + 1; priv->index_table[stream_id] = realloc(priv->index_table[stream_id], priv->index_malloc_size[stream_id]*sizeof(priv->index_table[0][0])); } if (priv->index_table_size[stream_id] > 0) { index = &priv->index_table[stream_id][priv->index_table_size[stream_id] - 1]; if (index->timestamp >= timestamp || index->offset >= offset) return; } index = &priv->index_table[stream_id][priv->index_table_size[stream_id]++]; index->timestamp = timestamp; index->offset = offset; }}static void add_index_segment(demuxer_t *demuxer, int seek_stream_id, int seek_timestamp){ int tag, len, stream_id, timestamp, flags; if (seek_timestamp != -1 && (unsigned)seek_stream_id >= MAX_STREAMS) return; while (1) { demuxer->filepos = stream_tell(demuxer->stream); tag = stream_read_dword(demuxer->stream); if (tag == MKTAG('A', 'T', 'A', 'D')) { stream_skip(demuxer->stream, 14); continue; /* skip to next loop */ } len = tag & 0xffff; if (tag == -256 || len < 12) break; stream_id = stream_read_word(demuxer->stream); timestamp = stream_read_dword(demuxer->stream); stream_skip(demuxer->stream, 1); /* reserved */ flags = stream_read_char(demuxer->stream); if (flags == -256) break; if (flags & 2) { add_index_item(demuxer, stream_id, timestamp, demuxer->filepos); if (stream_id == seek_stream_id && timestamp >= seek_timestamp) { stream_seek(demuxer->stream, demuxer->filepos); return; } } // printf("Index: stream=%d packet=%d timestamp=%d len=%d flags=0x%x datapos=0x%x\n", stream_id, entries, timestamp, len, flags, index->offset); /* skip data */ stream_skip(demuxer->stream, len-12); }}static int generate_index(demuxer_t *demuxer){ real_priv_t *priv = demuxer->priv; int origpos = stream_tell(demuxer->stream); int data_pos = priv->data_chunk_offset-10; int i; int tag; stream_seek(demuxer->stream, data_pos); tag = stream_read_dword(demuxer->stream); if (tag != MKTAG('A', 'T', 'A', 'D')) { mp_msg(MSGT_DEMUX, MSGL_WARN,"Something went wrong, no data chunk found on given address (%d)\n", data_pos); } else { stream_skip(demuxer->stream, 14); add_index_segment(demuxer, -1, -1); } for (i = 0; i < MAX_STREAMS; i++) { if (priv->index_table_size[i] > 0) { dump_index(demuxer, i); } } stream_reset(demuxer->stream); stream_seek(demuxer->stream, origpos); return 0;}#elsestatic int generate_index(demuxer_t *demuxer){ real_priv_t *priv = demuxer->priv; int origpos = stream_tell(demuxer->stream); int data_pos = priv->data_chunk_offset-10; int num_of_packets = 0; int i, entries = 0; int len, stream_id = 0, timestamp, flags; int tab_pos = 0;read_index: stream_seek(demuxer->stream, data_pos); i = stream_read_dword_le(demuxer->stream); if ((i == -256) || (i != MKTAG('D', 'A', 'T', 'A'))) { mp_msg(MSGT_DEMUX, MSGL_WARN,"Something went wrong, no data chunk found on given address (%d)\n", data_pos); goto end; } stream_skip(demuxer->stream, 4); /* chunk size */ stream_skip(demuxer->stream, 2); /* version */ num_of_packets = stream_read_dword(demuxer->stream); mp_msg(MSGT_DEMUX, MSGL_V,"Generating index table from raw data (pos: 0x%x) for %d packets\n", data_pos, num_of_packets); data_pos = stream_read_dword_le(demuxer->stream)-10; /* next data chunk */ for (i = 0; i < MAX_STREAMS; i++) { priv->index_table_size[i] = num_of_packets; priv->index_table[i] = malloc(priv->index_table_size[i] * sizeof(real_index_table_t));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -