mirror of https://github.com/mpv-player/mpv
implemented RoQ file demuxing
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@4452 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
parent
6bd8125163
commit
becadc7046
|
@ -3,7 +3,7 @@ LIBNAME = libmpdemux.a
|
||||||
|
|
||||||
include ../config.mak
|
include ../config.mak
|
||||||
|
|
||||||
SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c aviwrite.c demux_asf.c demux_avi.c demux_mov.c demux_mpg.c demux_viv.c demuxer.c dvdauth.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c
|
SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c aviwrite.c demux_asf.c demux_avi.c demux_mov.c demux_mpg.c demux_viv.c demuxer.c dvdauth.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c
|
||||||
ifeq ($(STREAMING),yes)
|
ifeq ($(STREAMING),yes)
|
||||||
SRCS += asf_streaming.c url.c http.c network.c rtp.c
|
SRCS += asf_streaming.c url.c http.c network.c rtp.c
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
RoQ file demuxer for the MPlayer program
|
||||||
|
by Mike Melanson
|
||||||
|
based on Dr. Tim Ferguson's RoQ document found at:
|
||||||
|
http://www.csse.monash.edu.au/~timf/videocodec.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
|
#define RoQ_INFO 0x1001
|
||||||
|
#define RoQ_QUAD_CODEBOOK 0x1002
|
||||||
|
#define RoQ_QUAD_VQ 0x1011
|
||||||
|
#define RoQ_SOUND_MONO 0x1020
|
||||||
|
#define RoQ_SOUND_STEREO 0x1021
|
||||||
|
|
||||||
|
#define CHUNK_TYPE_AUDIO 0
|
||||||
|
#define CHUNK_TYPE_VIDEO 1
|
||||||
|
|
||||||
|
#define RoQ_FPS 24
|
||||||
|
|
||||||
|
typedef struct roq_chunk_t
|
||||||
|
{
|
||||||
|
int chunk_type;
|
||||||
|
off_t chunk_offset;
|
||||||
|
int chunk_size;
|
||||||
|
} roq_chunk_t;
|
||||||
|
|
||||||
|
typedef struct roq_data_t
|
||||||
|
{
|
||||||
|
int total_chunks;
|
||||||
|
int current_chunk;
|
||||||
|
roq_chunk_t *chunks;
|
||||||
|
} roq_data_t;
|
||||||
|
|
||||||
|
// Check if a stream qualifies as a RoQ file based on the magic numbers
|
||||||
|
// at the start of the file:
|
||||||
|
// 84 10 FF FF FF FF 1E 00
|
||||||
|
int roq_check_file(demuxer_t *demuxer)
|
||||||
|
{
|
||||||
|
stream_reset(demuxer->stream);
|
||||||
|
stream_seek(demuxer->stream, 0);
|
||||||
|
|
||||||
|
if ((stream_read_dword(demuxer->stream) == 0x8410FFFF) &&
|
||||||
|
(stream_read_dword(demuxer->stream) == 0xFFFF1E00))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return value:
|
||||||
|
// 0 = EOF or no stream found
|
||||||
|
// 1 = successfully read a packet
|
||||||
|
int demux_roq_fill_buffer(demuxer_t *demuxer)
|
||||||
|
{
|
||||||
|
roq_data_t *roq_data = (roq_data_t *)demuxer->priv;
|
||||||
|
roq_chunk_t roq_chunk;
|
||||||
|
demux_stream_t *ds;
|
||||||
|
|
||||||
|
if (roq_data->current_chunk >= roq_data->total_chunks)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
roq_chunk = roq_data->chunks[roq_data->current_chunk];
|
||||||
|
if (roq_chunk.chunk_type == CHUNK_TYPE_AUDIO)
|
||||||
|
ds = demuxer->audio;
|
||||||
|
else
|
||||||
|
ds = demuxer->video;
|
||||||
|
|
||||||
|
// make sure we're at the right place in the stream and fetch the chunk
|
||||||
|
stream_seek(demuxer->stream, roq_chunk.chunk_offset);
|
||||||
|
ds_read_packet(
|
||||||
|
ds,
|
||||||
|
demuxer->stream,
|
||||||
|
roq_chunk.chunk_size,
|
||||||
|
// roq_data->current_frame/sh_video->fps,
|
||||||
|
0,
|
||||||
|
roq_chunk.chunk_offset,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
roq_data->current_chunk++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
demuxer_t* demux_open_roq(demuxer_t* demuxer)
|
||||||
|
{
|
||||||
|
sh_video_t *sh_video = NULL;
|
||||||
|
sh_audio_t *sh_audio = NULL;
|
||||||
|
|
||||||
|
roq_data_t *roq_data = (roq_data_t *)malloc(sizeof(roq_data_t));
|
||||||
|
int chunk_id;
|
||||||
|
int chunk_size;
|
||||||
|
int chunk_arg1;
|
||||||
|
int chunk_arg2;
|
||||||
|
int chunk_counter = 0;
|
||||||
|
int last_chunk_id = 0;
|
||||||
|
|
||||||
|
roq_data->chunks = NULL;
|
||||||
|
|
||||||
|
// position the stream and start traversing
|
||||||
|
stream_seek(demuxer->stream, 8);
|
||||||
|
while (!stream_eof(demuxer->stream))
|
||||||
|
{
|
||||||
|
chunk_id = stream_read_word_le(demuxer->stream);
|
||||||
|
chunk_size = stream_read_word_le(demuxer->stream);
|
||||||
|
chunk_arg1 = stream_read_word_le(demuxer->stream);
|
||||||
|
chunk_arg2 = stream_read_word_le(demuxer->stream);
|
||||||
|
|
||||||
|
// this is the only useful header info in the file
|
||||||
|
if (chunk_id == RoQ_INFO)
|
||||||
|
{
|
||||||
|
// there should only be one RoQ_INFO chunk per file
|
||||||
|
if (sh_video)
|
||||||
|
{
|
||||||
|
mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Found more than one RoQ_INFO chunk\n");
|
||||||
|
stream_skip(demuxer->stream, 8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// make the header first
|
||||||
|
sh_video = new_sh_video(demuxer, 0);
|
||||||
|
// make sure the demuxer knows about the new stream header
|
||||||
|
demuxer->video->sh = sh_video;
|
||||||
|
// make sure that the video demuxer stream header knows about its
|
||||||
|
// parent video demuxer stream
|
||||||
|
sh_video->ds = demuxer->video;
|
||||||
|
|
||||||
|
// this is a good opportunity to create a video stream header
|
||||||
|
sh_video->disp_w = stream_read_word_le(demuxer->stream);
|
||||||
|
sh_video->disp_h = stream_read_word_le(demuxer->stream);
|
||||||
|
stream_skip(demuxer->stream, 4);
|
||||||
|
|
||||||
|
// custom fourcc for internal MPlayer use
|
||||||
|
sh_video->format = mmioFOURCC('R', 'o', 'Q', 'V');
|
||||||
|
|
||||||
|
// constant frame rate
|
||||||
|
sh_video->fps = RoQ_FPS;
|
||||||
|
sh_video->frametime = 1 / RoQ_FPS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((chunk_id == RoQ_SOUND_MONO) ||
|
||||||
|
(chunk_id == RoQ_SOUND_STEREO))
|
||||||
|
{
|
||||||
|
// create the audio stream header if it hasn't been created it
|
||||||
|
if (sh_audio == NULL)
|
||||||
|
{
|
||||||
|
// make the header first
|
||||||
|
sh_audio = new_sh_audio(demuxer, 0);
|
||||||
|
// make sure the demuxer knows about the new stream header
|
||||||
|
demuxer->audio->sh = sh_audio;
|
||||||
|
// make sure that the audio demuxer stream header knows about its
|
||||||
|
// parent audio demuxer stream
|
||||||
|
sh_audio->ds = demuxer->audio;
|
||||||
|
|
||||||
|
// custom fourcc for internal MPlayer use
|
||||||
|
sh_audio->format = mmioFOURCC('R', 'o', 'Q', 'A');
|
||||||
|
// assume it's mono until there's reason to believe otherwise
|
||||||
|
sh_audio->channels = 1;
|
||||||
|
// always 22KHz, 16-bit
|
||||||
|
sh_audio->samplerate = 22050;
|
||||||
|
sh_audio->samplesize = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it's stereo, promote the channel number
|
||||||
|
if (chunk_id == RoQ_SOUND_STEREO)
|
||||||
|
sh_audio->channels = 2;
|
||||||
|
|
||||||
|
// index the chunk
|
||||||
|
roq_data->chunks = (roq_chunk_t *)realloc(roq_data->chunks,
|
||||||
|
(chunk_counter + 1) * sizeof (roq_chunk_t));
|
||||||
|
roq_data->chunks[chunk_counter].chunk_type = CHUNK_TYPE_AUDIO;
|
||||||
|
roq_data->chunks[chunk_counter].chunk_offset =
|
||||||
|
stream_tell(demuxer->stream) - 8;
|
||||||
|
roq_data->chunks[chunk_counter].chunk_size = chunk_size + 8;
|
||||||
|
|
||||||
|
stream_skip(demuxer->stream, chunk_size);
|
||||||
|
chunk_counter++;
|
||||||
|
}
|
||||||
|
else if ((chunk_id == RoQ_QUAD_CODEBOOK) ||
|
||||||
|
((chunk_id == RoQ_QUAD_VQ) && (last_chunk_id != RoQ_QUAD_CODEBOOK)))
|
||||||
|
{
|
||||||
|
// index a new chunk if it's a codebook or quad VQ not following a
|
||||||
|
// codebook
|
||||||
|
roq_data->chunks = (roq_chunk_t *)realloc(roq_data->chunks,
|
||||||
|
(chunk_counter + 1) * sizeof (roq_chunk_t));
|
||||||
|
roq_data->chunks[chunk_counter].chunk_type = CHUNK_TYPE_VIDEO;
|
||||||
|
roq_data->chunks[chunk_counter].chunk_offset =
|
||||||
|
stream_tell(demuxer->stream) - 8;
|
||||||
|
roq_data->chunks[chunk_counter].chunk_size = chunk_size + 8;
|
||||||
|
|
||||||
|
stream_skip(demuxer->stream, chunk_size);
|
||||||
|
chunk_counter++;
|
||||||
|
}
|
||||||
|
else if ((chunk_id == RoQ_QUAD_VQ) && (last_chunk_id == RoQ_QUAD_CODEBOOK))
|
||||||
|
{
|
||||||
|
// if it's a quad VQ chunk following a codebook chunk, extend the last
|
||||||
|
// chunk
|
||||||
|
roq_data->chunks[chunk_counter - 1].chunk_size += (chunk_size + 8);
|
||||||
|
stream_skip(demuxer->stream, chunk_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Unknown RoQ chunk ID: %04X\n", chunk_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_chunk_id = chunk_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
roq_data->total_chunks = chunk_counter;
|
||||||
|
roq_data->current_chunk = 0;
|
||||||
|
|
||||||
|
demuxer->priv = roq_data;
|
||||||
|
|
||||||
|
return demuxer;
|
||||||
|
}
|
|
@ -150,6 +150,7 @@ void ds_read_packet(demux_stream_t *ds,stream_t *stream,int len,float pts,off_t
|
||||||
// return value:
|
// return value:
|
||||||
// 0 = EOF or no stream found or invalid type
|
// 0 = EOF or no stream found or invalid type
|
||||||
// 1 = successfully read a packet
|
// 1 = successfully read a packet
|
||||||
|
int demux_roq_fill_buffer(demuxer_t *demux);
|
||||||
int demux_film_fill_buffer(demuxer_t *demux);
|
int demux_film_fill_buffer(demuxer_t *demux);
|
||||||
int demux_fli_fill_buffer(demuxer_t *demux);
|
int demux_fli_fill_buffer(demuxer_t *demux);
|
||||||
int demux_mpg_es_fill_buffer(demuxer_t *demux);
|
int demux_mpg_es_fill_buffer(demuxer_t *demux);
|
||||||
|
@ -176,6 +177,7 @@ int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){
|
||||||
// Note: parameter 'ds' can be NULL!
|
// Note: parameter 'ds' can be NULL!
|
||||||
// printf("demux->type=%d\n",demux->type);
|
// printf("demux->type=%d\n",demux->type);
|
||||||
switch(demux->type){
|
switch(demux->type){
|
||||||
|
case DEMUXER_TYPE_ROQ: return demux_roq_fill_buffer(demux);
|
||||||
case DEMUXER_TYPE_FILM: return demux_film_fill_buffer(demux);
|
case DEMUXER_TYPE_FILM: return demux_film_fill_buffer(demux);
|
||||||
case DEMUXER_TYPE_FLI: return demux_fli_fill_buffer(demux);
|
case DEMUXER_TYPE_FLI: return demux_fli_fill_buffer(demux);
|
||||||
case DEMUXER_TYPE_MPEG_ES: return demux_mpg_es_fill_buffer(demux);
|
case DEMUXER_TYPE_MPEG_ES: return demux_mpg_es_fill_buffer(demux);
|
||||||
|
@ -367,11 +369,13 @@ int mov_check_file(demuxer_t* demuxer);
|
||||||
int mov_read_header(demuxer_t* demuxer);
|
int mov_read_header(demuxer_t* demuxer);
|
||||||
int demux_open_fli(demuxer_t* demuxer);
|
int demux_open_fli(demuxer_t* demuxer);
|
||||||
int demux_open_film(demuxer_t* demuxer);
|
int demux_open_film(demuxer_t* demuxer);
|
||||||
|
int demux_open_roq(demuxer_t* demuxer);
|
||||||
|
|
||||||
extern int vivo_check_file(demuxer_t *demuxer);
|
extern int vivo_check_file(demuxer_t *demuxer);
|
||||||
extern void demux_open_vivo(demuxer_t *demuxer);
|
extern void demux_open_vivo(demuxer_t *demuxer);
|
||||||
extern int y4m_check_file(demuxer_t *demuxer);
|
extern int y4m_check_file(demuxer_t *demuxer);
|
||||||
extern void demux_open_y4m(demuxer_t *demuxer);
|
extern void demux_open_y4m(demuxer_t *demuxer);
|
||||||
|
extern int roq_check_file(demuxer_t *demuxer);
|
||||||
|
|
||||||
extern int real_check_file(demuxer_t *demuxer);
|
extern int real_check_file(demuxer_t *demuxer);
|
||||||
extern void demux_open_real(demuxer_t *demuxer);
|
extern void demux_open_real(demuxer_t *demuxer);
|
||||||
|
@ -462,7 +466,7 @@ if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_VIVO){
|
||||||
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_REAL){
|
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_REAL){
|
||||||
demuxer=new_demuxer(stream,DEMUXER_TYPE_REAL,audio_id,video_id,dvdsub_id);
|
demuxer=new_demuxer(stream,DEMUXER_TYPE_REAL,audio_id,video_id,dvdsub_id);
|
||||||
if(real_check_file(demuxer)){
|
if(real_check_file(demuxer)){
|
||||||
mp_msg(MSGT_DEMUXER,MSGL_INFO,"Detected REAL file format!\n");
|
mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_DetectedREALfile);
|
||||||
file_format=DEMUXER_TYPE_REAL;
|
file_format=DEMUXER_TYPE_REAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -492,6 +496,14 @@ if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_FILM){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//=============== Try to open as RoQ file: =================
|
||||||
|
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_ROQ){
|
||||||
|
demuxer=new_demuxer(stream,DEMUXER_TYPE_ROQ,audio_id,video_id,dvdsub_id);
|
||||||
|
if(roq_check_file(demuxer)){
|
||||||
|
mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_DetectedROQfile);
|
||||||
|
file_format=DEMUXER_TYPE_ROQ;
|
||||||
|
}
|
||||||
|
}
|
||||||
//=============== Try to open as MPEG-PS file: =================
|
//=============== Try to open as MPEG-PS file: =================
|
||||||
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_PS){
|
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_PS){
|
||||||
int pes=1;
|
int pes=1;
|
||||||
|
@ -574,6 +586,10 @@ switch(file_format){
|
||||||
if (!demux_open_film(demuxer)) return NULL;
|
if (!demux_open_film(demuxer)) return NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DEMUXER_TYPE_ROQ: {
|
||||||
|
if (!demux_open_roq(demuxer)) return NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DEMUXER_TYPE_MOV: {
|
case DEMUXER_TYPE_MOV: {
|
||||||
if(!mov_read_header(demuxer)) return NULL;
|
if(!mov_read_header(demuxer)) return NULL;
|
||||||
// sh_video=d_video->sh;if(sh_video) sh_video->ds=d_video;
|
// sh_video=d_video->sh;if(sh_video) sh_video->ds=d_video;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#define DEMUXER_TYPE_Y4M 12
|
#define DEMUXER_TYPE_Y4M 12
|
||||||
#define DEMUXER_TYPE_NUV 13
|
#define DEMUXER_TYPE_NUV 13
|
||||||
#define DEMUXER_TYPE_FILM 14
|
#define DEMUXER_TYPE_FILM 14
|
||||||
|
#define DEMUXER_TYPE_ROQ 15
|
||||||
|
|
||||||
#define DEMUXER_TIME_NONE 0
|
#define DEMUXER_TIME_NONE 0
|
||||||
#define DEMUXER_TIME_PTS 1
|
#define DEMUXER_TIME_PTS 1
|
||||||
|
|
Loading…
Reference in New Issue