full source package, you can download from here
http://cooleyes.fx-world.org/downloads/ ... ecoder.rar
Code: Select all
/* 
 *	Copyright (C) 2008 cooleyes
 *	[email protected] 
 *
 *  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 "common/mem64.h"
#include "pspmpeg.h"
#include "mp4_read.h"
int SetupCallbacks();
PSP_MODULE_INFO("AVCDecoder", 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 nal_prefix_size;
	ScePVoid nal_buffer;
	SceInt32 nal_size;
	SceInt32 mode;
} Mp4AvcNalStruct;
typedef struct {
	SceInt32 unknown0;
	SceInt32 unknown1;
	SceInt32 width;
	SceInt32 height;
	SceInt32 unknown4;
	SceInt32 unknown5;
	SceInt32 unknown6;
	SceInt32 unknown7;
	SceInt32 unknown8;
	SceInt32 unknown9;
} Mp4AvcInfoStruct;
typedef struct {
	ScePVoid buffer0;
	ScePVoid buffer1;
	ScePVoid buffer2;
	ScePVoid buffer3;
	ScePVoid buffer4;
	ScePVoid buffer5;
	ScePVoid buffer6;
	ScePVoid buffer7;
	SceInt32 unknown0;
	SceInt32 unknown1;
	SceInt32 unknown2;
} Mp4AvcYuvStruct;
typedef struct {
	SceInt32 unknown0;
	SceInt32 unknown1;
	SceInt32 unknown2;
	SceInt32 unknown3;
	Mp4AvcInfoStruct* info_buffer;
	SceInt32 unknown5;
	SceInt32 unknown6;
	SceInt32 unknown7;
	SceInt32 unknown8;
	SceInt32 unknown9;
	SceInt32 unknown10;
	Mp4AvcYuvStruct* 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;
} Mp4AvcDetail2Struct;
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;
} Mp4AvcCscStruct;
typedef struct {
	int      mpeg_init;
	int      mpeg_create;
	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;
	ScePVoid mpeg_sps_pps_buffer;
	SceInt32 mpeg_sps_size;
	SceInt32 mpeg_pps_size;
	SceInt32 mpeg_nal_prefix_size;
	Mp4AvcDetail2Struct* mpeg_detail2;
	SceInt32 mpeg_pic_num;
} Mp4AvcDecoderStruct;
Mp4AvcDecoderStruct avc_struct;
Mp4AvcDecoderStruct* avc = &avc_struct;
Mp4AvcCscStruct csc_struct;
Mp4AvcCscStruct* csc = &csc_struct;
struct mp4_read_struct reader;
unsigned long __attribute__((aligned(64))) RGBBuffer0[768*480];
unsigned long __attribute__((aligned(64))) RGBBuffer1[768*480];
unsigned char* FrameBuffer[] = {RGBBuffer0, RGBBuffer1};
int frame_index = 0;
char filename[1024];
typedef struct tagBITMAPFILEHEADER {
        unsigned long   bfSize;
        unsigned long   bfReserved;
        unsigned long   bfOffBits;
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER{
	unsigned long	biSize;
	long	biWidth;
	long	biHeight;
	unsigned short	biPlanes;
	unsigned short	biBitCount;
	unsigned long	biCompression;
	unsigned long	biSizeImage;
	long	biXPelsPerMeter;
	long	biYPelsPerMeter;
	unsigned long	biClrUsed;
	unsigned long	biClrImportant;
} BITMAPINFOHEADER;
unsigned char bm[2] = {0x42, 0x4D};
BITMAPFILEHEADER h1;
BITMAPINFOHEADER h2;
void convertRGBBuffer(void* src, void* dest, int w, int h) {
	unsigned long* src_p = (unsigned long*)src;
	unsigned long* dest_p = (unsigned long*)dest;
	
	int x,y;
	unsigned long point;
	unsigned char a, b, g, r;
	for(y = 0; y < h; y++) {
		for(x = 0; x < w; x++ ) {
			point = src_p[y*w+x];
			a = (unsigned char)( ( point >> 24 ) & 0xFF );
			b = (unsigned char)( ( point >> 16 ) & 0xFF );
			g = (unsigned char)( ( point >> 8 ) & 0xFF );
			r = (unsigned char)( ( point ) & 0xFF );
			point = a;
			point = (point << 8 ) | r;
			point = (point << 8 ) | g;
			point = (point << 8 ) | b; 
			dest_p[(h-1-y)*w+x] = point;
		}
	}
}
int main(void)
{
	SetupCallbacks();
	
	pspDebugScreenInit();
	pspDebugScreenSetXY(0, 2);
	
	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);
	
	int devkitVersion = sceKernelDevkitVersion();
	if ( devkitVersion < 0x03050000)
		strcat(filename, "/mpeg_vsh330.prx");
	else if ( devkitVersion < 0x03070000)
		strcat(filename, "/mpeg_vsh350.prx");
	else
		strcat(filename, "/mpeg_vsh370.prx");
	
	pspDebugScreenPrintf("%s\n", filename);
	
	mp4_read_safe_constructor(&reader);
	memset(avc, 0, sizeof(Mp4AvcDecoderStruct));
	
	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;
	}
	
	
	getcwd(filename, 256);
	strcat(filename, "/cooleyesBridge.prx");
	modid = sceKernelLoadModule(filename, 0, NULL);
	if(modid >= 0) {
		modid = sceKernelStartModule(modid, 0, 0, &status, NULL);
	}
	else {
		pspDebugScreenPrintf("\nerr=0x%08X : sceKernelLoadModule(cooleyesBridge)\n", modid);
		goto wait;
	}
	
	char* res;
	res = mp4_read_open(&reader, "ms0:/VIDEO/Test.MP4");
	if ( res ) {
		pspDebugScreenPrintf("mp4_read_open : %s\n", res);
		goto wait;
	}
	
	pspDebugScreenPrintf("video width %d, height %d\n",
		reader.file.video_width,
		reader.file.video_height);
		
	if ( reader.file.info->tracks[reader.file.video_track_id]->avc_profile == 0x4D && 
		(reader.file.video_width > 480 || reader.file.video_height > 272 ) ) {
		//set ME to main profile 480P mode
		cooleyesMeBootStart(devkitVersion, 1);
		avc->mpeg_mode = 5;
	}
	else if (reader.file.info->tracks[reader.file.video_track_id]->avc_profile == 0x4D ){
		//set ME to main profile mode ( <=480*272 )
		cooleyesMeBootStart(devkitVersion, 3);
		avc->mpeg_mode = 4;
	}
	else if ( reader.file.info->tracks[reader.file.video_track_id]->avc_profile == 0x42 ) {
		//set ME to baseline profile mode ( <=480*272 )
		cooleyesMeBootStart(devkitVersion, 4);
		avc->mpeg_mode = 4;
	}
	
	result = sceMpegInit();
	if ( result != 0 ){
		pspDebugScreenPrintf("\nerr: sceMpegInit=0x%08X\n", result);
		goto wait;
	}
	
	avc->mpeg_ddrtop =  memalign(0x400000, 0x400000);
	avc->mpeg_au_buffer = avc->mpeg_ddrtop + 0x10000;
	
	result = sceMpegQueryMemSize(avc->mpeg_mode);
	if ( result < 0 ){
		pspDebugScreenPrintf("\nerr: sceMpegQueryMemSize(0x%08X)=0x%08X\n", avc->mpeg_mode, result);
		goto wait;
	}
	
	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(...)=0x%08X\n", result);
		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(...)=0x%08X\n", result);
		goto wait;
	}
	
	unsigned char* nal_buffer = (unsigned char*)malloc_64(1024*1024);
	
	pspDebugScreenPrintf("sps %d, pps %d, nal_prefix %d\n",
		reader.file.info->tracks[reader.file.video_track_id]->avc_sps_size,
		reader.file.info->tracks[reader.file.video_track_id]->avc_pps_size,
		reader.file.info->tracks[reader.file.video_track_id]->avc_nal_prefix_size);
	
	avc->mpeg_sps_size = reader.file.info->tracks[reader.file.video_track_id]->avc_sps_size;
	avc->mpeg_pps_size = reader.file.info->tracks[reader.file.video_track_id]->avc_pps_size;
	avc->mpeg_nal_prefix_size = reader.file.info->tracks[reader.file.video_track_id]->avc_nal_prefix_size;
	avc->mpeg_sps_pps_buffer = malloc_64(avc->mpeg_sps_size + avc->mpeg_pps_size);
	if ( avc->mpeg_sps_pps_buffer == 0 ) {
		goto wait;
	}
	memcpy(avc->mpeg_sps_pps_buffer, reader.file.info->tracks[reader.file.video_track_id]->avc_sps, avc->mpeg_sps_size);
	memcpy(avc->mpeg_sps_pps_buffer+avc->mpeg_sps_size, reader.file.info->tracks[reader.file.video_track_id]->avc_pps, avc->mpeg_pps_size);
	
	
	Mp4AvcNalStruct nal;
	int frame_count = 0;
	int output_frame = 0;
	sceCtrlReadBufferPositive(&input, 1);
	
	struct mp4_video_read_output_struct v_packet;
	
	while(!(input.Buttons & PSP_CTRL_TRIANGLE)) {
		
		nal.sps_buffer = avc->mpeg_sps_pps_buffer;
		nal.sps_size = avc->mpeg_sps_size;
		nal.pps_buffer = avc->mpeg_sps_pps_buffer+avc->mpeg_sps_size;
		nal.pps_size = avc->mpeg_pps_size;
		nal.nal_prefix_size = avc->mpeg_nal_prefix_size;
		
		res = mp4_read_get_video(&reader, frame_count, &v_packet);
		if (res != 0)
			break;
		
		nal.nal_buffer = v_packet.video_buffer;
		nal.nal_size = v_packet.video_length ;
		if ( frame_count == 0 )
			nal.mode = 3;
		else
			nal.mode = 0;
	
		result = sceMpegGetAvcNalAu(&avc->mpeg, &nal, avc->mpeg_au);
		pspDebugScreenPrintf(" GetAvcNalAu=0x%08X\n", result);
	
		result = sceMpegAvcDecode(&avc->mpeg, avc->mpeg_au, 512, 0, &avc->mpeg_pic_num);
		pspDebugScreenPrintf(" AvcDecode=0x%08X,0x%08X\n", result, avc->mpeg_pic_num);
		
		result = sceMpegAvcDecodeDetail2(&avc->mpeg, &avc->mpeg_detail2);
		pspDebugScreenPrintf(" AvcDecodeDetail2=0x%08X, ErrCode=%d\n", result, avc->mpeg_detail2->unknown2);
		pspDebugScreenPrintf(" Decode width=%d, height=%d\n", avc->mpeg_detail2->info_buffer->width, avc->mpeg_detail2->info_buffer->height);
		char rgb_filename[512];
		if ( avc->mpeg_pic_num > 0 ) {
			int i;
			for( i = 0; i < avc->mpeg_pic_num; i++ ) {
				Mp4AvcCscStruct csc;
				csc.height = (avc->mpeg_detail2->info_buffer->height+15) >> 4;
				csc.width = (avc->mpeg_detail2->info_buffer->width+15) >> 4;
				csc.mode0 = 0;
				csc.mode1 = 0;
				csc.buffer0 = avc->mpeg_detail2->yuv_buffer->buffer0 ;
				csc.buffer1 = avc->mpeg_detail2->yuv_buffer->buffer1 ;
				csc.buffer2 = avc->mpeg_detail2->yuv_buffer->buffer2 ;
				csc.buffer3 = avc->mpeg_detail2->yuv_buffer->buffer3 ;
				csc.buffer4 = avc->mpeg_detail2->yuv_buffer->buffer4 ;
				csc.buffer5 = avc->mpeg_detail2->yuv_buffer->buffer5 ;
				csc.buffer6 = avc->mpeg_detail2->yuv_buffer->buffer6 ;
				csc.buffer7 = avc->mpeg_detail2->yuv_buffer->buffer7 ;
				int csc_width = (avc->mpeg_mode == 4) ? 512 : 768;
				int bmp_width = (avc->mpeg_mode == 4) ? 512 : 768;
				int bmp_height = reader.file.video_height;
				if ( sceMpegBaseCscAvc(RGBBuffer0, 0, csc_width, &csc) == 0 ) {
					memset(rgb_filename, 0, 512);
					sprintf(rgb_filename, "ms0:/PICTURE/%dx%d.output_frame%d.bmp", 
						reader.file.video_width,
						reader.file.video_height,
						output_frame);
					output_frame++;
					FILE* fp_rgb = fopen(rgb_filename, "wb");
					
					fwrite(bm, 2, 1, fp_rgb);
	
					h1.bfSize = 4 * bmp_width * bmp_height + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 2;
					h1.bfReserved = 0;
					h1.bfOffBits = 2 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
				
					h2.biSize = sizeof(BITMAPINFOHEADER);
					h2.biPlanes = 1;
					h2.biBitCount = 32;
					h2.biCompression = 0;
					h2.biWidth = bmp_width;
					h2.biHeight = bmp_height;
					h2.biSizeImage = 3 * bmp_width * bmp_height;
					h2.biXPelsPerMeter = 0xEC4;
					h2.biYPelsPerMeter = 0xEC4;
					h2.biClrUsed = 0;
					h2.biClrImportant = 0;
				
					fwrite(&h1, sizeof(BITMAPFILEHEADER), 1, fp_rgb);
					fwrite(&h2, sizeof(BITMAPINFOHEADER), 1, fp_rgb);
					
					convertRGBBuffer(RGBBuffer0, RGBBuffer1, bmp_width, bmp_height);
					
					fwrite(RGBBuffer1, 4*bmp_width*bmp_height, 1, fp_rgb);
					fclose(fp_rgb);
				}
			}			
		}
		
		++frame_count;
		if ( frame_count >= 5 ) 
			break;
	}
	
	
wait:
	mp4_read_close(&reader);
		
	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;
}
