full source package, you can download from here
http://cooleyes.fx-world.org/downloads/ ... ecoder.rar
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 "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;
}