changeset 4451:5627d5b58083

implemented RoQ file demuxing
author melanson
date Fri, 01 Feb 2002 05:35:16 +0000
parents 3da8c5706371
children bef7b760bc80
files libmpdemux/Makefile libmpdemux/demux_roq.c libmpdemux/demuxer.c libmpdemux/demuxer.h
diffstat 4 files changed, 243 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/Makefile	Fri Feb 01 05:33:46 2002 +0000
+++ b/libmpdemux/Makefile	Fri Feb 01 05:35:16 2002 +0000
@@ -3,7 +3,7 @@
 
 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)
 SRCS += asf_streaming.c url.c http.c network.c rtp.c
 endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpdemux/demux_roq.c	Fri Feb 01 05:35:16 2002 +0000
@@ -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;
+}
--- a/libmpdemux/demuxer.c	Fri Feb 01 05:33:46 2002 +0000
+++ b/libmpdemux/demuxer.c	Fri Feb 01 05:35:16 2002 +0000
@@ -150,6 +150,7 @@
 // return value:
 //     0 = EOF or no stream found or invalid type
 //     1 = successfully read a packet
+int demux_roq_fill_buffer(demuxer_t *demux);
 int demux_film_fill_buffer(demuxer_t *demux);
 int demux_fli_fill_buffer(demuxer_t *demux);
 int demux_mpg_es_fill_buffer(demuxer_t *demux);
@@ -176,6 +177,7 @@
   // Note: parameter 'ds' can be NULL!
 //  printf("demux->type=%d\n",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_FLI: return demux_fli_fill_buffer(demux);
     case DEMUXER_TYPE_MPEG_ES: return demux_mpg_es_fill_buffer(demux);
@@ -367,11 +369,13 @@
 int mov_read_header(demuxer_t* demuxer);
 int demux_open_fli(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 void demux_open_vivo(demuxer_t *demuxer);
 extern int y4m_check_file(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 void demux_open_real(demuxer_t *demuxer);
@@ -462,7 +466,7 @@
 if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_REAL){
   demuxer=new_demuxer(stream,DEMUXER_TYPE_REAL,audio_id,video_id,dvdsub_id);
   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;
   }
 }
@@ -492,6 +496,14 @@
     }
   }
 }
+//=============== 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: =================
 if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_PS){
  int pes=1;
@@ -574,6 +586,10 @@
   if (!demux_open_film(demuxer)) return NULL;
   break;
  }
+ case DEMUXER_TYPE_ROQ: {
+  if (!demux_open_roq(demuxer)) return NULL;
+  break;
+ }
  case DEMUXER_TYPE_MOV: {
   if(!mov_read_header(demuxer)) return NULL;
 //  sh_video=d_video->sh;if(sh_video) sh_video->ds=d_video;
--- a/libmpdemux/demuxer.h	Fri Feb 01 05:33:46 2002 +0000
+++ b/libmpdemux/demuxer.h	Fri Feb 01 05:35:16 2002 +0000
@@ -17,6 +17,7 @@
 #define DEMUXER_TYPE_Y4M 12
 #define DEMUXER_TYPE_NUV 13
 #define DEMUXER_TYPE_FILM 14
+#define DEMUXER_TYPE_ROQ 15
 
 #define DEMUXER_TIME_NONE 0
 #define DEMUXER_TIME_PTS 1