forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

a new sample to decode all psp supported MP4AVC

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
cooleyes



Joined: 18 May 2006
Posts: 125

PostPosted: Mon Feb 09, 2009 1:16 am    Post subject: a new sample to decode all psp supported MP4AVC Reply with quote

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
View user's profile Send private message
Pirata Nervo



Joined: 09 Oct 2007
Posts: 409

PostPosted: Mon Feb 09, 2009 3:20 am    Post subject: Reply with quote

Thanks for sharing and good work :D
_________________

Upgrade your PSP
Back to top
View user's profile Send private message
victorprosa



Joined: 14 Jan 2009
Posts: 38

PostPosted: Mon Feb 09, 2009 3:30 am    Post subject: Reply with quote

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
View user's profile Send private message Send e-mail
Shapyi



Joined: 25 Apr 2005
Posts: 95

PostPosted: Mon Feb 09, 2009 7:28 am    Post subject: Reply with quote

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
View user's profile Send private message
cooleyes



Joined: 18 May 2006
Posts: 125

PostPosted: Mon Feb 09, 2009 10:56 am    Post subject: Reply with quote

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
View user's profile Send private message
cooleyes



Joined: 18 May 2006
Posts: 125

PostPosted: Mon Feb 09, 2009 11:03 am    Post subject: Reply with quote

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
View user's profile Send private message
ctszy



Joined: 12 Apr 2008
Posts: 18

PostPosted: Tue Feb 10, 2009 2:05 am    Post subject: Reply with quote

THX 4 sharing, Great Work :)
Back to top
View user's profile Send private message
slasher2661996



Joined: 22 Feb 2009
Posts: 91
Location: Melbourne Australia ZOMG

PostPosted: Sun Feb 22, 2009 9:54 am    Post subject: Reply with quote

WARNINGS DO! MATTER!!![/i][/b]
Back to top
View user's profile Send private message
NoEffex



Joined: 27 Nov 2008
Posts: 108

PostPosted: Sun Feb 22, 2009 10:25 am    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
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