[MPlayer-dev-eng] PMP demuxer for mplayer

wan0eve wan0eve at 126.com
Sun Aug 3 11:57:06 CEST 2008


I wrote a patch to make mplayer support pmp file, a type of media file in  
PSP(PlayStation Portable).

I hope it can be add to mplayer.


Index: libmpdemux/demux_pmp.c
===================================================================
--- libmpdemux/demux_pmp.c	(revision 0)
+++ libmpdemux/demux_pmp.c	(revision 0)
@@ -0,0 +1,492 @@
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+#include "stream/stream.h"
+#include "demuxer.h"
+#include "stheader.h"
+#include "ebml.h"
+
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "vobsub.h"
+#include "subreader.h"
+#include "libvo/sub.h"
+
+#include "libass/ass.h"
+#include "libass/ass_mp.h"
+
+#include "libavutil/common.h"
+
+#include "libavutil/lzo.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/avstring.h"
+
+#define minimum_buffer_size       262144
+
+struct pmp_signature_struct
+{
+    unsigned int pmpm;
+    unsigned int version;
+};
+
+struct pmp_video_struct
+{
+    unsigned int format;
+    unsigned int number_of_frames;
+    unsigned int width;
+    unsigned int height;
+    unsigned int scale;
+    unsigned int rate;
+};
+
+struct pmp_audio_struct
+{
+    unsigned int format;
+    unsigned int number_of_streams;
+    unsigned int maximum_number_of_frames;
+    unsigned int scale;
+    unsigned int rate;
+    unsigned int stereo;
+};
+
+struct pmp_header_struct
+{
+    struct pmp_signature_struct signature;
+    struct pmp_video_struct     video;
+    struct pmp_audio_struct     audio;
+};
+
+struct pmp_stream_struct
+{
+    struct pmp_header_struct header;
+
+    unsigned int *packet_index;
+    unsigned int  packet_start;
+    unsigned int  maximum_packet_size;
+};
+
+typedef struct
+{
+    uint8_t number_of_audio_frames;
+    unsigned int  first_delay;
+    unsigned int  last_delay;
+    unsigned int  video_length;
+} pmp_packet_header_t;
+
+typedef struct
+{
+    struct pmp_stream_struct stream;
+    unsigned int  current_video_frame;
+    unsigned int  current_audio_frame;
+    unsigned int  current_audio_packet;
+	unsigned int  buffer_size;
+    unsigned int  first_packet;
+    unsigned int  first_packet_position;
+	unsigned int *packet_header;
+} pmp_demuxer_t;
+
+static void pmp_demux_safe_constructor(pmp_demuxer_t *p)
+{
+    p->current_video_frame = 0;
+    p->current_audio_frame = 0;
+    p->current_audio_packet = 0;
+    p->stream.packet_index = 0;
+}
+
+static void pmp_demux_close(pmp_demuxer_t *p)
+{
+    if (p->stream.packet_index)
+        free(p->stream.packet_index);
+
+    if(p->packet_header)
+        free(p->packet_header);
+
+    pmp_demux_safe_constructor(p);
+}
+
+static int check_header_v1(struct pmp_header_struct header)
+{
+    if (header.video.format  < 0 || header.video.format  > 1)
+       return 0;
+    if (header.video.number_of_frames == 0)         return 0;
+    if (header.video.width            == 0)         return 0;
+    if (header.video.height           == 0)         return 0;
+    if (header.video.scale            == 0)         return 0;
+    if (header.video.rate             == 0)         return 0;
+
+    if (header.video.rate  < header.video.scale)    return 0;
+    if (header.video.scale > 0xffffff)              return 0;
+
+    if ((header.video.width  % 8) != 0)             return 0;
+    if ((header.video.height % 8) != 0)             return 0;
+    if (header.video.width        >  720)           return 0;
+    if (header.video.height       >  512)           return 0;
+
+    if (header.audio.format   < 0 || header.audio.format > 1)
+        return 0;
+    if (header.audio.number_of_streams        == 0) return 0;
+    if (header.audio.maximum_number_of_frames == 0) return 0;
+    if (header.audio.format == 0 && header.audio.scale  != 1152) return 0;
+    if (header.audio.format == 1 && header.audio.scale  != 1024) return 0;
+    if (header.audio.rate   != 44100)               return 0;
+    if (header.audio.stereo != 1)                   return 0;
+    return 1;
+}
+
+FILE *fd = NULL;
+static demuxer_t* demux_pmp_open (demuxer_t *demuxer)
+{
+    stream_t *s = demuxer->stream;
+    pmp_demuxer_t *p;
+    p = calloc (1, sizeof (pmp_demuxer_t));
+    pmp_demux_safe_constructor(p);
+
+    stream_seek(s, s->start_pos);
+    if(stream_eof(s)) return NULL;
+
+    int header_len = sizeof(struct pmp_header_struct);
+
+    if (stream_read(s, &p->stream.header, header_len) != header_len)
+        return NULL;
+    if (p->stream.header.signature.pmpm    != 0x6d706d70)
+        return NULL;
+    if (p->stream.header.signature.version != 1)
+        return NULL;
+
+    if(p->stream.header.signature.version == 1)
+    {
+        if(!check_header_v1(p->stream.header))
+            return NULL;
+    }
+
+    int number_of_frames = sizeof(unsigned int) *  
p->stream.header.video.number_of_frames;
+
+    p->stream.packet_index = malloc(number_of_frames);
+    if (!p->stream.packet_index)
+    {
+        pmp_demux_close(p);
+        return NULL;
+    }
+
+    if (stream_read(s, p->stream.packet_index, number_of_frames) !=  
number_of_frames)
+    {
+        pmp_demux_close(p);
+        return NULL;
+    }
+
+    p->stream.packet_start  = header_len + number_of_frames;
+    p->stream.maximum_packet_size = p->stream.packet_index[0] >> 1;
+
+    unsigned int i = 0;
+    unsigned int packet_size = 0;
+
+    for ( ; i < p->stream.header.video.number_of_frames; i++)
+    {
+        if ((p->stream.packet_index[i] >> 1) >  
p->stream.maximum_packet_size)
+            p->stream.maximum_packet_size = p->stream.packet_index[i] >>  
1;
+        packet_size += p->stream.packet_index[i] >> 1;
+    }
+
+    p->buffer_size = minimum_buffer_size;
+    if (p->stream.maximum_packet_size > p->buffer_size)
+        p->buffer_size = p->stream.maximum_packet_size;
+
+    p->packet_header = malloc(sizeof(unsigned int) *  
(p->stream.header.audio.maximum_number_of_frames *  
p->stream.header.audio.number_of_streams + 3));
+    if (!p->packet_header)
+    {
+        pmp_demux_close(p);
+        return NULL;
+    }
+
+    p->first_packet = 0;
+    p->first_packet_position = p->stream.packet_start;
+
+    demuxer->priv = p;
+
+    sh_video_t *sh_video = new_sh_video(demuxer, 0);
+
+    if (demuxer->video->id == -1) demuxer->video->id = 0;
+    if (demuxer->video->id == 0)
+    demuxer->video->sh = sh_video;
+    sh_video->ds = demuxer->video;
+
+    sh_video->disp_w = p->stream.header.video.width;
+    sh_video->disp_h = p->stream.header.video.height;
+    if(p->stream.header.video.format == 0)
+        sh_video->format = mmioFOURCC('m', 'p', '4', 'v');
+    else
+        sh_video->format = mmioFOURCC('a', 'v', 'c', '1');
+    double video_scale = p->stream.header.video.scale;
+    double video_rate = p->stream.header.video.rate;
+    sh_video->frametime = video_scale / video_rate;
+    sh_video->fps = 1.0 / sh_video->frametime;
+
+    sh_video->bih = calloc (1, sizeof (BITMAPINFOHEADER));
+    sh_video->bih->biSize = sizeof (BITMAPINFOHEADER);
+    sh_video->bih->biWidth = p->stream.header.video.width;
+    sh_video->bih->biHeight = p->stream.header.video.height;
+    sh_video->bih->biSizeImage = sh_video->bih->biWidth *  
sh_video->bih->biHeight * sh_video->bih->biBitCount/8;
+    sh_video->bih->biCompression = sh_video->format;
+    sh_video->bih->biBitCount = 24;
+    sh_video->aspect = (float)sh_video->bih->biWidth /  
(float)sh_video->bih->biHeight;
+
+    if (p->stream.header.audio.number_of_streams > 0)
+    {
+        sh_audio_t *sh_audio = new_sh_audio(demuxer, 0);
+        demuxer->audio->id = 0;
+        demuxer->audio->sh = sh_audio;
+        sh_audio->ds = demuxer->audio;
+        sh_audio->wf = malloc (sizeof (WAVEFORMATEX));
+        memset(sh_audio->wf, 0, sizeof (WAVEFORMATEX));
+        sh_audio->samplerate = sh_audio->wf->nSamplesPerSec = (uint32_t)  
p->stream.header.audio.rate;
+        sh_audio->wf->nAvgBytesPerSec = 16000;
+        sh_audio->channels = sh_audio->wf->nChannels = 2;
+        sh_audio->wf->nBlockAlign = p->stream.header.audio.scale;
+        if(p->stream.header.audio.format == 1)
+            sh_audio->format = sh_audio->wf->wFormatTag = mmioFOURCC('m',  
'p', '4', 'a');
+        else
+            sh_audio->format = sh_audio->wf->wFormatTag = 0x0055;
+    }
+
+    return demuxer;
+}
+
+static void demux_pmp_close (demuxer_t *demuxer)
+{
+    pmp_demuxer_t *pmp_d = (pmp_demuxer_t *) demuxer->priv;
+    if(pmp_d)
+    {
+        pmp_demux_close(pmp_d);
+        free(pmp_d);
+    }
+}
+
+static unsigned int get_packet_position(pmp_demuxer_t *pmp_d , int audio)
+{
+	unsigned int first_packet          = pmp_d->first_packet;
+	unsigned int first_packet_position = pmp_d->first_packet_position;
+    unsigned int packet = 0;
+    if(audio)
+        packet = pmp_d->current_audio_frame;
+    else
+        packet = pmp_d->current_video_frame;
+
+	if (packet >= first_packet)
+	{
+		while (first_packet != packet)
+		{
+			first_packet_position += pmp_d->stream.packet_index[first_packet] >> 1;
+			first_packet ++;
+		}
+	}
+	else
+	{
+		while (first_packet != packet)
+		{
+			first_packet --;
+			first_packet_position -= pmp_d->stream.packet_index[first_packet] >> 1;
+		}
+	}
+    return first_packet_position;
+}
+
+static int demux_pmp_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds)
+{
+    pmp_demuxer_t *p = demuxer->priv;
+
+    /* Video */
+    if (ds == demuxer->video)
+    {
+        if(p->current_video_frame >  
p->stream.header.video.number_of_frames)
+            return 0;
+        sh_video_t* sh = demuxer->video->sh;
+        stream_t *s = demuxer->stream;
+        unsigned int framepos = get_packet_position(p , 0);
+        pmp_packet_header_t header;
+        stream_seek(s, framepos);
+        stream_read(s, &header.number_of_audio_frames, 1);
+        stream_read(s, &header.first_delay, 4);
+        stream_read(s, &header.last_delay, 4);
+        stream_read(s, &header.video_length, 4);
+        unsigned int videopos = framepos + 1 + 4 + 4 + 4 +  
4*header.number_of_audio_frames* p->stream.header.audio.number_of_streams;
+        unsigned int len = header.video_length;
+        stream_seek(s, videopos);
+        demux_packet_t *dp = new_demux_packet(len);
+        len = stream_read(s, dp->buffer, len);
+        resize_demux_packet(dp, len);
+        dp->pts = p->current_video_frame / sh->fps;
+        ds_add_packet(ds, dp);
+        p->current_video_frame++;
+    }
+
+    /* Audio */
+    if (ds == demuxer->audio)
+    {
+        if(p->current_audio_frame >  
p->stream.header.video.number_of_frames)
+            return 0;
+        sh_audio_t *sh_audio = ds->sh;
+        sh_video_t* sh = demuxer->video->sh;
+        stream_t *s = demuxer->stream;
+        unsigned int framepos = get_packet_position(p , 1);
+        pmp_packet_header_t header;
+        stream_seek(s, framepos);
+        stream_read(s, &header.number_of_audio_frames, 1);
+        stream_read(s, &header.first_delay, 4);
+        stream_read(s, &header.last_delay, 4);
+        stream_read(s, &header.video_length, 4);
+
+        unsigned int audiopos = framepos + 1 + 4 + 4 + 4 +  
4*header.number_of_audio_frames* p->stream.header.audio.number_of_streams  
+ header.video_length;
+        unsigned int len = 0;
+
+        if(p->stream.header.audio.format == 1)
+        {
+            int padding = 7;
+            uint8_t aac_hdr[7] = {0xff, 0xf9, 0x50, 0x80, 0, 0, 0xfc};
+            stream_read(s, &len, 4);
+            aac_hdr[4] = (len >> 3) + 1;
+            aac_hdr[5] = (len << 5) - 1;
+            stream_seek(s, audiopos);
+            demux_packet_t *dp = new_demux_packet(len + padding);
+			memcpy(dp->buffer, aac_hdr, padding);
+            len = stream_read(s, &dp->buffer[padding], len);
+            audiopos += len;
+            resize_demux_packet(dp, len + padding);
+            ds_add_packet(ds, dp);
+            int i= 1;
+            unsigned int audio_length;
+            while(i < header.number_of_audio_frames)
+            {
+                stream_seek(s, framepos + 1 + 4 + 4 + 4 + 4 *i);
+                stream_read(s, &audio_length, 4);
+                aac_hdr[4] = (audio_length >> 3) + 1;
+                aac_hdr[5] = (audio_length << 5) - 1;
+                stream_seek(s, audiopos);
+                demux_packet_t *dp = new_demux_packet(audio_length +  
padding);
+			    memcpy(dp->buffer, aac_hdr, padding);
+                audio_length = stream_read(s, &dp->buffer[padding],  
audio_length);
+                audiopos += audio_length;
+                resize_demux_packet(dp, audio_length + padding);
+                ds_add_packet(ds, dp);
+                ++i;
+            }
+        }
+        else
+        {
+            int i = 0;
+            unsigned int audio_length;
+            while(i < header.number_of_audio_frames)
+            {
+                i++;
+                stream_read(s, &audio_length, 4);
+                len += audio_length;
+            }
+            stream_seek(s, audiopos);
+            demux_packet_t *dp = new_demux_packet(len);
+            len = stream_read(s, dp->buffer, len);
+            resize_demux_packet(dp, len);
+            ds_add_packet(ds, dp);
+        }
+        p->current_audio_frame++;
+    }
+
+    return 1;
+}
+
+static int demux_pmp_control(demuxer_t *demuxer, int cmd, void *arg)
+{
+    sh_video_t *sh_video=demuxer->video->sh;
+    sh_audio_t *sh_audio=demuxer->audio->sh;
+    pmp_demuxer_t *pmp_d = demuxer->priv;
+
+    switch(cmd)
+    {
+        case DEMUXER_CTRL_GET_TIME_LENGTH:
+        {
+            double video_frames =  
pmp_d->stream.header.video.number_of_frames;
+            double video_scale = pmp_d->stream.header.video.scale;
+            double video_rate = pmp_d->stream.header.video.rate;
+
+            double res = 0;
+            if(sh_video)
+                res = (video_frames * video_scale + video_rate/2) /  
video_rate;
+            *((double *)arg) = res;
+            return DEMUXER_CTRL_OK;
+        }
+        case DEMUXER_CTRL_GET_PERCENT_POS:
+        {
+            int video_frames =  
pmp_d->stream.header.video.number_of_frames;
+            if (sh_video)
+                *((int *)arg) = pmp_d->current_video_frame * 100 /  
video_frames;
+            return DEMUXER_CTRL_OK;
+        }
+    default:
+        return DEMUXER_CTRL_NOTIMPL;
+    }
+}
+
+static void demux_pmp_seek(demuxer_t *demuxer,float rel_seek_secs,float  
audio_delay,int flags)
+{
+    sh_video_t *sh_video=demuxer->video->sh;
+    if(!sh_video)
+        return;
+    pmp_demuxer_t *pmp_d = demuxer->priv;
+    double video_pos = (double)pmp_d->current_video_frame / sh_video->fps;
+    double duration = (double)pmp_d->stream.header.video.number_of_frames  
/ sh_video->fps;
+
+    if (flags&SEEK_ABSOLUTE) video_pos=0;
+    if (flags&SEEK_FACTOR) rel_seek_secs *= duration;
+
+    video_pos += rel_seek_secs;
+    if (video_pos < 0) video_pos = 0;
+
+    pmp_d->current_video_frame = FFMIN(video_pos * sh_video->fps,  
pmp_d->stream.header.video.number_of_frames);
+    pmp_d->current_audio_frame = pmp_d->current_video_frame;
+    sh_video->num_frames_decoded = pmp_d->current_video_frame;
+    sh_video->num_frames = pmp_d->current_video_frame;
+}
+
+static int pmp_check_file(demuxer_t *demuxer)
+{
+    mp_msg(MSGT_DEMUX, MSGL_V, "PMP: Checking for PlayStation Media  
%s\n", demuxer->filename);
+
+    if (!demuxer->filename) return 0;
+
+    stream_t *s = demuxer->stream;
+
+    stream_seek(s, s->start_pos);
+    if(stream_eof(s)) return NULL;
+
+    struct pmp_header_struct header;
+
+    int header_len = sizeof(struct pmp_header_struct);
+
+    if (stream_read(s, &header, header_len) != header_len)
+        return 0;
+
+    if (header.signature.pmpm    == 0x6d706d70)
+        return DEMUXER_TYPE_PMP;
+
+    return 0;
+}
+
+const demuxer_desc_t demuxer_desc_pmp = {
+  "PMP demuxer",
+  "pmp",
+  "PSP Media file",
+  "William Wang",
+  "",
+  DEMUXER_TYPE_PMP,
+  0, // safe autodetect
+  pmp_check_file,
+  demux_pmp_fill_buffer,
+  demux_pmp_open,
+  demux_pmp_close,
+  demux_pmp_seek,
+  demux_pmp_control
+};
Index: libmpdemux/demuxer.c
===================================================================
--- libmpdemux/demuxer.c	(revision 27401)
+++ libmpdemux/demuxer.c	(working copy)
@@ -80,6 +80,7 @@
  extern const demuxer_desc_t demuxer_desc_lavf_preferred;
  extern const demuxer_desc_t demuxer_desc_aac;
  extern const demuxer_desc_t demuxer_desc_nut;
+extern const demuxer_desc_t demuxer_desc_pmp;

  /* Please do not add any new demuxers here. If you want to implement a new
   * demuxer, add it to libavformat, except for wrappers around external
@@ -152,6 +153,7 @@
  #ifdef HAVE_XMMS
      &demuxer_desc_xmms,
  #endif
+    &demuxer_desc_pmp,
      /* Please do not add any new demuxers here. If you want to implement  
a new
       * demuxer, add it to libavformat, except for wrappers around external
       * libraries and demuxers requiring binary support. */
Index: libmpdemux/demuxer.h
===================================================================
--- libmpdemux/demuxer.h	(revision 27401)
+++ libmpdemux/demuxer.h	(working copy)
@@ -63,11 +63,12 @@
  #define DEMUXER_TYPE_NUT 43
  #define DEMUXER_TYPE_LAVF_PREFERRED 44
  #define DEMUXER_TYPE_RTP_NEMESI 45
+#define DEMUXER_TYPE_PMP 46

  // This should always match the higest demuxer type number.
  // Unless you want to disallow users to force the demuxer to some types
  #define DEMUXER_TYPE_MIN 0
-#define DEMUXER_TYPE_MAX 45
+#define DEMUXER_TYPE_MAX 46

  #define DEMUXER_TYPE_DEMUXERS (1<<16)
  // A virtual demuxer type for the network code
Index: Makefile
===================================================================
--- Makefile	(revision 27401)
+++ Makefile	(working copy)
@@ -199,6 +199,7 @@
                libmpdemux/demux_viv.c \
                libmpdemux/demux_vqf.c \
                libmpdemux/demux_y4m.c \
+              libmpdemux/demux_pmp.c \
                libmpdemux/ebml.c \
                libmpdemux/extension.c \
                libmpdemux/mf.c \





-- 
William Wang




More information about the MPlayer-dev-eng mailing list