to decode mp4(avc), we need a mpeg_vsh.prx from psp fw (ver > 2.00)
so I use the mpeg_vsh.prx from psp fw(3.30),
I decompress and decrypt mpeg_vsh.prx from psp fw(3.30) and rename to mpeg_vsh330.prx , and use it to decode mp4(avc)
now, I can decode <=480*272 avc frame from psp mp4 file,
and I am trying to decode 720*480 avc frame from psp mp4 file.
Code: Select all
/*
* Copyright (C) 2008 cooleyes
* eyes.cooleyes@gmail.com
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include <pspkernel.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <psputils.h>
#include <pspgu.h>
#include <pspdebug.h>
#include <psppower.h>
#include <stdio.h>
#include <stdlib.h>
#include <psprtc.h>
#include <pspsdk.h>
#include <string.h>
#include <malloc.h>
#include "mem64.h"
#include "pspmpeg/pspmpeg.h"
#include "mp4ff.h"
int SetupCallbacks();
PSP_MODULE_INFO("avcdecode test", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(0);
PSP_HEAP_SIZE_KB(18*1024);
SceCtrlData input;
typedef struct {
ScePVoid sps_buffer;
SceInt32 sps_size;
ScePVoid pps_buffer;
SceInt32 pps_size;
SceInt32 unkown0;
ScePVoid nal_buffer;
SceInt32 nal_size;
SceInt32 mode;
} AvcNalStruct;
typedef struct {
SceInt32 unknown0;
SceInt32 unknown1;
SceInt32 width;
SceInt32 height;
SceInt32 unknown4;
SceInt32 unknown5;
SceInt32 unknown6;
SceInt32 unknown7;
SceInt32 unknown8;
SceInt32 unknown9;
} AvcInfoStruct;
typedef struct {
ScePVoid buffer0;
ScePVoid buffer1;
ScePVoid buffer2;
ScePVoid buffer3;
ScePVoid buffer4;
ScePVoid buffer5;
ScePVoid buffer6;
ScePVoid buffer7;
SceInt32 unknown0;
SceInt32 unknown1;
SceInt32 unknown2;
} AvcYuvStruct;
typedef struct {
SceInt32 unknown0;
SceInt32 unknown1;
SceInt32 unknown2;
SceInt32 unknown3;
AvcInfoStruct* info_buffer;
SceInt32 unknown5;
SceInt32 unknown6;
SceInt32 unknown7;
SceInt32 unknown8;
SceInt32 unknown9;
SceInt32 unknown10;
AvcYuvStruct* yuv_buffer;
SceInt32 unknown12;
SceInt32 unknown13;
SceInt32 unknown14;
SceInt32 unknown15;
SceInt32 unknown16;
SceInt32 unknown17;
SceInt32 unknown18;
SceInt32 unknown19;
SceInt32 unknown20;
SceInt32 unknown21;
SceInt32 unknown22;
SceInt32 unknown23;
} AvcCodecStruct;
typedef struct {
SceInt32 height;
SceInt32 width;
SceInt32 mode0;
SceInt32 mode1;
ScePVoid buffer0;
ScePVoid buffer1;
ScePVoid buffer2;
ScePVoid buffer3;
ScePVoid buffer4;
ScePVoid buffer5;
ScePVoid buffer6;
ScePVoid buffer7;
} AvcCscStruct;
typedef struct {
ScePVoid mpeg_buffer;
SceMpeg mpeg;
SceMpegRingbuffer mpeg_ringbuffer;
SceMpegAu* mpeg_au;
SceInt32 mpeg_mode;
SceInt32 mpeg_buffer_size;
ScePVoid mpeg_ddrtop;
ScePVoid mpeg_au_buffer;
AvcNalStruct mpeg_nal;
AvcCodecStruct* mpeg_codec_buffer;
AvcYuvStruct* mpeg_yuv_buffer;
AvcInfoStruct* mpeg_info_buffer;
} AvcDecodeStruct;
static uint32_t mp4_read(void *user_data, void *buffer, uint32_t length) {
FILE** fp = (FILE**)user_data;
uint32_t res = fread(buffer, length, 1, *fp);
return (res*length);
}
static uint32_t mp4_seek(void *user_data, uint64_t position) {
FILE** fp = (FILE**)user_data;
return fseek(*fp, position, PSP_SEEK_SET );
}
AvcDecodeStruct avc_struct;
AvcDecodeStruct* avc = &avc_struct;
AvcCscStruct csc_struct;
AvcCscStruct* csc = &csc_struct;
//unsigned char RGBBuffer[4*512*512];
unsigned char RGBBuffer0[4*512*272];
unsigned char RGBBuffer1[4*512*272];
unsigned char* FrameBuffer[] = {RGBBuffer0, RGBBuffer1};
int frame_index = 0;
char filename[1024];
mp4ff_callback_t mp4_callback = {mp4_read, 0, mp4_seek, 0, 0};
int main(void)
{
SetupCallbacks();
pspDebugScreenInit();
pspDebugScreenSetXY(0, 2);
//scePowerSetClockFrequency(333,333,166);
//scePowerSetCpuClockFrequency(333);
//scePowerSetBusClockFrequency(166);
scePowerSetClockFrequency(133,133,66);
scePowerSetCpuClockFrequency(133);
scePowerSetBusClockFrequency(66);
u32 cpu = scePowerGetCpuClockFrequency();
u32 bus = scePowerGetBusClockFrequency();
pspDebugScreenPrintf("cpu=%d, bus=%d\n", cpu, bus);
getcwd(filename, 256);
strcat(filename, "/mpeg_vsh330.prx");
pspDebugScreenPrintf("%s\n", filename);
FILE* mp4_file = fopen("ms0:/VIDEO/Test.MP4", "rb");
mp4_callback.user_data = &mp4_file;
mp4ff_t* mp4_handle = mp4ff_open_read(&mp4_callback);
u32 total_tracks = mp4ff_total_tracks(mp4_handle);
pspDebugScreenPrintf("total_tracks=%d\n", total_tracks);
int ii;
for(ii = 0; ii < total_tracks; ii++) {
pspDebugScreenPrintf("track%d : type 0x%08X\n", ii, mp4ff_get_track_type(mp4_handle, ii));
pspDebugScreenPrintf("track%d : %d samples\n", ii, mp4ff_num_samples(mp4_handle, ii));
}
u32 total_samples = mp4ff_num_samples(mp4_handle, 0);
unsigned char* sps_pps_buffer;
unsigned int sps_size, pps_size;
if ( mp4ff_get_avc_sps_pps(mp4_handle, 0, &sps_pps_buffer, &sps_size, &pps_size) != 0 || sps_size == 0 || pps_size == 0 ) {
pspDebugScreenPrintf("\nerr: get_avc_sps_pps\n");
goto wait;
}
//pspDebugScreenPrintf("sps_size=%d, pps_size=%d\n", sps_size, pps_size);
int result;
result = sceUtilityLoadAvModule(0);
if ( result < 0 ) {
pspDebugScreenPrintf("\nerr: sceUtilityLoadAvModule(0)\n");
goto wait;
}
SceUID modid;
int status;
modid = sceKernelLoadModule(filename, 0, NULL);
if(modid >= 0) {
modid = sceKernelStartModule(modid, 0, 0, &status, NULL);
}
else {
pspDebugScreenPrintf("\nerr=0x%08X : sceKernelLoadModule\n", modid);
goto wait;
}
// result = pspSdkLoadStartModule("ms0:/mpeg_vsh330.prx", PSP_MEMORY_PARTITION_USER);
// result = sceUtilityLoadAvModule(3);
// if ( result < 0 ){
// pspDebugScreenPrintf("\nerr=0x%08X : sceUtilityLoadAvModule(3)\n", result);
// goto wait;
// }
result = sceMpegInit();
if ( result != 0 ){
pspDebugScreenPrintf("\nerr: sceMpegInit\n");
goto wait;
}
avc->mpeg_mode = 4;
// avc->mpeg_ddrtop = 0x09400000;
// avc->mpeg_au_buffer = 0x09410000;
avc->mpeg_ddrtop = memalign(0x400000, 0x400000);
avc->mpeg_au_buffer = avc->mpeg_ddrtop + 0x10000;
// pspDebugScreenPrintf("\naddress=0x%08X\n", avc->mpeg_au_buffer);
result = sceMpegQueryMemSize(avc->mpeg_mode);
if ( result < 0 ){
pspDebugScreenPrintf("\nerr: sceMpegQueryMemSize(0x%08X)\n", avc->mpeg_mode);
goto wait;
}
// pspDebugScreenPrintf("\n%d\n", result);
avc->mpeg_buffer_size = result;
if ( (result & 0xF) != 0 )
result = (result & 0xFFFFFFF0) + 16;
avc->mpeg_buffer = malloc_64(result);
if ( avc->mpeg_buffer == 0 ) {
pspDebugScreenPrintf("\nerr: alloc\n");
goto wait;
}
result = sceMpegCreate(&avc->mpeg, avc->mpeg_buffer, avc->mpeg_buffer_size, &avc->mpeg_ringbuffer, 512, avc->mpeg_mode, avc->mpeg_ddrtop);
if ( result != 0){
pspDebugScreenPrintf("\nerr: sceMpegCreate\n");
goto wait;
}
avc->mpeg_au = (SceMpegAu*)malloc_64(64);
if ( avc->mpeg_au == 0 ) {
pspDebugScreenPrintf("\nerr: alloc\n");
goto wait;
}
memset(avc->mpeg_au, 0xFF, 64);
if ( sceMpegInitAu(&avc->mpeg, avc->mpeg_au_buffer, avc->mpeg_au) != 0 ){
pspDebugScreenPrintf("\nerr: sceMpegInitAu\n");
goto wait;
}
unsigned char* nal_buffer = (unsigned char*)malloc_64(1024*1024);
// unsigned char sps_pps_buffer[27];
//
// FILE* fp;
// fp = fopen("ms0:/sps_pps.dat", "rb");
// fread(sps_pps_buffer, 27, 1, fp);
// fclose(fp);
// sps_size = 23;
// pps_size = 4;
//---------------------------------------------------------------------------------//
float curr_ms = 1.0f;
u64 last_tick;
sceRtcGetCurrentTick(&last_tick);
u32 tick_frequency = sceRtcGetTickResolution();
int frame_count = 0;
sceCtrlReadBufferPositive(&input, 1);
int pic_num;
sceDisplayWaitVblankStart();
sceDisplaySetFrameBuf(FrameBuffer[frame_index], 512, PSP_DISPLAY_PIXEL_FORMAT_8888, PSP_DISPLAY_SETBUF_IMMEDIATE);
while(!(input.Buttons & PSP_CTRL_TRIANGLE)) {
float curr_fps = 1.0f / curr_ms;
//pspDebugScreenSetXY(0,0);
//pspDebugScreenPrintf("fps: %d.%03d \n",(int)curr_fps,(int)((curr_fps-(int)curr_fps) * 1000.0f));
avc->mpeg_nal.sps_buffer = (&sps_pps_buffer[0]);
avc->mpeg_nal.sps_size = sps_size;
avc->mpeg_nal.pps_buffer = (&sps_pps_buffer[sps_size]);
avc->mpeg_nal.pps_size = pps_size;
avc->mpeg_nal.unkown0 = 4;
memset(nal_buffer, 0, 1024*1024);
mp4ff_read_sample_v2(mp4_handle, 0, frame_count, nal_buffer);
avc->mpeg_nal.nal_buffer = nal_buffer;
avc->mpeg_nal.nal_size = mp4ff_read_sample_getsize(mp4_handle, 0, frame_count);//size1 ;
if ( frame_count == 0 )
avc->mpeg_nal.mode = 3;
else
avc->mpeg_nal.mode = 0;
FILE* fp1;
// memset(filename,0,1024);
// sprintf(filename, "ms0:/mpeg%d_0.dat", frame_count);
// fp1 = fopen(filename, "wb");
// fwrite(p1, 512, 1, fp1);
// fclose(fp1);
result = sceMpegGetAvcNalAu(&avc->mpeg, &avc->mpeg_nal, avc->mpeg_au);
memset(filename,0,1024);
// sprintf(filename, "ms0:/au%d_1.dat", frame_count);
// fp1 = fopen(filename, "wb");
// fwrite(au0, 64, 1, fp1);
// fclose(fp1);
// pspDebugScreenPrintf(" GetAvcNalAu=0x%08X\n", result);
result = sceMpegAvcDecode(&avc->mpeg, avc->mpeg_au, 512, 0, &pic_num);
// pspDebugScreenPrintf(" AvcDecode=0x%08X,0x%08X\n", result, pic_num);
result = sceMpegAvcDecodeDetail2(&avc->mpeg, &avc->mpeg_codec_buffer);
// pspDebugScreenPrintf(" AvcDecodeDetail2=0x%08X\n", result);
if ( result == 0 ) {
avc->mpeg_yuv_buffer = avc->mpeg_codec_buffer->yuv_buffer;
avc->mpeg_info_buffer = avc->mpeg_codec_buffer->info_buffer;
if ( pic_num > 0 ) {
int i;
for(i=0;i<pic_num;i++) {
int csc_mode = 0;//i % 2;
csc->height = avc->mpeg_info_buffer->height >> 4;
csc->width = avc->mpeg_info_buffer->width >> 4;
csc->mode0 = csc_mode;
csc->mode1 = csc_mode;
if ( csc_mode == 0 ) {
csc->buffer0 = avc->mpeg_yuv_buffer->buffer0 ;
csc->buffer1 = avc->mpeg_yuv_buffer->buffer1 ;
csc->buffer2 = avc->mpeg_yuv_buffer->buffer2 ;
csc->buffer3 = avc->mpeg_yuv_buffer->buffer3 ;
csc->buffer4 = avc->mpeg_yuv_buffer->buffer4 ;
csc->buffer5 = avc->mpeg_yuv_buffer->buffer5 ;
csc->buffer6 = avc->mpeg_yuv_buffer->buffer6 ;
csc->buffer7 = avc->mpeg_yuv_buffer->buffer7 ;
}
else {
csc->buffer0 = avc->mpeg_yuv_buffer->buffer2 ;
csc->buffer1 = avc->mpeg_yuv_buffer->buffer3 ;
csc->buffer2 = avc->mpeg_yuv_buffer->buffer0 ;
csc->buffer3 = avc->mpeg_yuv_buffer->buffer1 ;
csc->buffer4 = avc->mpeg_yuv_buffer->buffer6 ;
csc->buffer5 = avc->mpeg_yuv_buffer->buffer7 ;
csc->buffer6 = avc->mpeg_yuv_buffer->buffer4 ;
csc->buffer7 = avc->mpeg_yuv_buffer->buffer5 ;
}
result = sceMpegBaseCscAvc(FrameBuffer[frame_index],0,512,csc);
// pspDebugScreenPrintf(" BaseCscAvc=0x%08X\n", result);
if ( result == 0 ) {
// memset(filename,0,1024);
// sprintf(filename, "ms0:/RGB%d.%d.dat", frame_count,i);
// fp1 = fopen(filename, "wb");
// fwrite(RGBBuffer, 4*512*512, 1, fp1);
// fclose(fp1);
sceDisplayWaitVblankStart();
sceDisplaySetFrameBuf(FrameBuffer[frame_index], 512, PSP_DISPLAY_PIXEL_FORMAT_8888, PSP_DISPLAY_SETBUF_IMMEDIATE);
frame_index = (frame_index+1) % 2;
//sceKernelDelayThread(10000);
}
}
}
}
// memset(filename,0,1024);
// sprintf(filename, "ms0:/mpeg%d.dat", frame_count);
// fp1 = fopen(filename, "wb");
// fwrite(p1, 512, 1, fp1);
// fclose(fp1);
++frame_count;
if ( frame_count >= total_samples )
break;
u64 curr_tick;
sceRtcGetCurrentTick(&curr_tick);
if ((curr_tick-last_tick) >= tick_frequency)
{
float time_span = ((int)(curr_tick-last_tick)) / (float)tick_frequency;
curr_ms = time_span / frame_count;
//frame_count = 0;
sceRtcGetCurrentTick(&last_tick);
}
sceCtrlReadBufferPositive(&input, 1);
}
// fclose(fp);
wait:
mp4ff_close(mp4_handle);
fclose(mp4_file);
pspDebugScreenPrintf("\n");
pspDebugScreenPrintf("press triangle to exit...\n");
sceCtrlReadBufferPositive(&input, 1);
while(!(input.Buttons & PSP_CTRL_TRIANGLE))
{
sceKernelDelayThread(10000); // wait 10 milliseconds
sceCtrlReadBufferPositive(&input, 1);
}
sceKernelExitGame();
return 0;
}
/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
sceKernelExitGame();
return 0;
}
/* Callback thread */
int CallbackThread(SceSize args, void *argp)
{
int cbid;
cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
sceKernelRegisterExitCallback(cbid);
sceKernelSleepThreadCB();
return 0;
}
/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
int thid = 0;
thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
if(thid >= 0)
{
sceKernelStartThread(thid, 0, 0);
}
return thid;
}
Code: Select all
TARGET = AvcDecodeTest
OBJS = main.o mem64.o mpegbase.o
BUILD_PRX = 1
PSP_FW_VERSION=371
CFLAGS = -G0 -Wall -O2
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
INCDIR = ./mp4ff/include
LIBDIR = .
LDFLAGS =
LIBS= -lpsppower -lm -lpsprtc -lpspgu -lpspmpeg -lmp4ff
EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = AvcDecode Test
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak