 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
cooleyes
Joined: 18 May 2006 Posts: 125
|
Posted: Mon Feb 09, 2009 1:16 am Post subject: a new sample to decode all psp supported MP4AVC |
|
|
Here is a sample code to decode a psp mp4(avc) file.
full source package, you can download from here
http://cooleyes.fx-world.org/downloads/samples/avcdecoder.rar
| Code: |
/*
* 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;
}
|
|
|
| Back to top |
|
 |
Pirata Nervo
Joined: 09 Oct 2007 Posts: 409
|
Posted: Mon Feb 09, 2009 3:20 am Post subject: |
|
|
Thanks for sharing and good work :D _________________
Upgrade your PSP |
|
| Back to top |
|
 |
victorprosa
Joined: 14 Jan 2009 Posts: 38
|
Posted: Mon Feb 09, 2009 3:30 am Post subject: |
|
|
Thank you VERY VERY much cooleyes
EDIT:
Cooleyes, i had some bad blocks when compiled the original source:
| Code: |
main.c:156: warning: initialization from incompatible pointer type
main.c:156: warning: initialization from incompatible pointer type
main.c: In function ‘main’:
main.c:223: warning: implicit declaration of function ‘getcwd’
main.c:239: warning: implicit declaration of function ‘sceUtilityLoadAvModule’
main.c:282: warning: implicit declaration of function ‘cooleyesMeBootStart’
main.c:323: warning: passing argument 7 of ‘sceMpegCreate’ makes integer from pointer without a cast
main.c:385: warning: implicit declaration of function ‘sceMpegGetAvcNalAu’
main.c:391: warning: implicit declaration of function ‘sceMpegAvcDecodeDetail2’
main.c:414: warning: implicit declaration of function ‘sceMpegBaseCscAvc’
main.c:340: warning: unused variable ‘nal_buffer’
|
| Code: |
mp4_read.c: In function ‘audio_swap_asynchronous_buffers’:
mp4_read.c:198: warning: initialization from incompatible pointer type
mp4_read.c:200: warning: assignment from incompatible pointer type
|
Anyway to solve this, or just don't matter with it?, as soon, as everything (eboot, param and PRX) was created... |
|
| Back to top |
|
 |
Shapyi
Joined: 25 Apr 2005 Posts: 95
|
Posted: Mon Feb 09, 2009 7:28 am Post subject: |
|
|
| Great work, thanks for sharing. Does this just work with AVC or does it work with both MPEG4-ASP and H.264? Have you discovered a similar method for decoding standard MPEG4 with resolutions above 480x272? Because I remember seeing this thread awhile back, it would be great to decode XviD using the PSP's built in hardware if possible. |
|
| Back to top |
|
 |
cooleyes
Joined: 18 May 2006 Posts: 125
|
Posted: Mon Feb 09, 2009 10:56 am Post subject: |
|
|
| victorprosa wrote: | Thank you VERY VERY much cooleyes
EDIT:
Cooleyes, i had some bad blocks when compiled the original source:
| Code: |
main.c:156: warning: initialization from incompatible pointer type
main.c:156: warning: initialization from incompatible pointer type
main.c: In function ‘main’:
main.c:223: warning: implicit declaration of function ‘getcwd’
main.c:239: warning: implicit declaration of function ‘sceUtilityLoadAvModule’
main.c:282: warning: implicit declaration of function ‘cooleyesMeBootStart’
main.c:323: warning: passing argument 7 of ‘sceMpegCreate’ makes integer from pointer without a cast
main.c:385: warning: implicit declaration of function ‘sceMpegGetAvcNalAu’
main.c:391: warning: implicit declaration of function ‘sceMpegAvcDecodeDetail2’
main.c:414: warning: implicit declaration of function ‘sceMpegBaseCscAvc’
main.c:340: warning: unused variable ‘nal_buffer’
|
| Code: |
mp4_read.c: In function ‘audio_swap_asynchronous_buffers’:
mp4_read.c:198: warning: initialization from incompatible pointer type
mp4_read.c:200: warning: assignment from incompatible pointer type
|
Anyway to solve this, or just don't matter with it?, as soon, as everything (eboot, param and PRX) was created... |
it just warning, don't matter with it. |
|
| Back to top |
|
 |
cooleyes
Joined: 18 May 2006 Posts: 125
|
Posted: Mon Feb 09, 2009 11:03 am Post subject: |
|
|
| Shapyi wrote: | | Great work, thanks for sharing. Does this just work with AVC or does it work with both MPEG4-ASP and H.264? Have you discovered a similar method for decoding standard MPEG4 with resolutions above 480x272? Because I remember seeing this thread awhile back, it would be great to decode XviD using the PSP's built in hardware if possible. |
I will try, but I can't promise it. |
|
| Back to top |
|
 |
ctszy
Joined: 12 Apr 2008 Posts: 18
|
Posted: Tue Feb 10, 2009 2:05 am Post subject: |
|
|
| THX 4 sharing, Great Work :) |
|
| Back to top |
|
 |
slasher2661996
Joined: 22 Feb 2009 Posts: 91 Location: Melbourne Australia ZOMG
|
Posted: Sun Feb 22, 2009 9:54 am Post subject: |
|
|
| WARNINGS DO! MATTER!!![/i][/b] |
|
| Back to top |
|
 |
NoEffex
Joined: 27 Nov 2008 Posts: 108
|
Posted: Sun Feb 22, 2009 10:25 am Post subject: |
|
|
| slasher2661996 wrote: | | WARNINGS DO! MATTER!!![/i][/b] | Sometimes. Other times they are indeed just warnings and are more of an annoyance than anything.
Anyways, very nice, and thank you for sharing this..complex piece of code, and licensing it under the GPL :D. _________________ Programming with:
Geany + Latest PSPSDK from svn |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|