[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