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
