ps2sdk  1.1
A collection of Open Source libraries used for developing applications on Sony's PlayStation 2® (PS2).
mpeg.c
Go to the documentation of this file.
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright (c) 2006-2007 Eugene Plotnikov <e-plotnikov@operamail.com>
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
9 #
10 # Simplest example of MPEG bitstream deconing/display
11 # Note: the program expects raw mpeg video data as it does not perform
12 # any demuxing. Only 4:2:0 colorspace is supported by the MPEG
13 # decoder. Scalable extensions are not supported either.
14 # Test bitstreams can be obtained for free at ftp://ftp.tek.com/tv/test/streams/Element/MPEG-Video-Conformance/main-profile/
15 # This program was only tested on SCPH-3004R PAL console.
16 # For real life usage of 'libmpeg' refer SMS project.
17 */
18 #include "libmpeg.h"
19 
20 #include <dma_tags.h>
21 #include <gif_tags.h>
22 #include <gs_psm.h>
23 #include <gs_gp.h>
24 
25 #include <kernel.h>
26 #include <dma.h>
27 #include <draw.h>
28 #include <fileio.h>
29 #include <malloc.h>
30 #include <graph.h>
31 #include <packet.h>
32 #include <stdio.h>
33 
34 #define MPEG_BITSTREAM_FILE "host:test.bin"
35 /* get the whole file (or first 24MB) into memory for simplicity */
36 #define MAX_SIZE ( 1024 * 1024 * 24 )
37 
38 typedef struct InitCBParam {
39 
41  void* m_pData;
44  int m_TexAddr;
45 
46 } InitCBParam;
47 
48 static unsigned char* s_pMPEGData;
49 static unsigned char* s_pTransferPtr;
50 static unsigned int s_MPEGDataSize;
51 
52 static int SetDMA ( void* );
53 static void* InitCB ( void*, MPEGSequenceInfo* );
54 
55 int main ( void ) {
56 /* read file (or part of it ) into memory */
57  packet_t *lPck;
58  qword_t *q;
59  framebuffer_t frame;
60  zbuffer_t z;
61  InitCBParam lInfo;
62  int lFD = open ( MPEG_BITSTREAM_FILE, O_RDONLY );
63  long lSize;
64  s64 lPTS, lCurPTS;
65 
66  frame.width = 640;
67  frame.height = 512;
68  frame.mask = 0;
69  frame.psm = GS_PSM_32;
70  frame.address = graph_vram_allocate(frame.width,frame.height, frame.psm, GRAPH_ALIGN_PAGE);
71 
72  z.enable = 0;
73  z.mask = 0;
74  z.method = 0;
75  z.zsm = 0;
76  z.address = 0;
77 
78  lPck = packet_init(100, PACKET_NORMAL);
79 
80  if ( lFD < 0 ) {
81  printf ( "test_mpeg: could not open '%s'\n", MPEG_BITSTREAM_FILE );
82  goto end;
83  } /* end if */
84 
85  lSize = lseek ( lFD, 0, SEEK_END );
86  lseek ( lFD, 0, SEEK_SET );
87 
88  if ( lSize <= 0 ) {
89  printf ( "test_mpeg: could not obtain file size (%ld)\n", lSize );
90  goto end;
91  } /* end if */
92 
93  s_pMPEGData = ( unsigned char* )malloc ( lSize = lSize > MAX_SIZE ? MAX_SIZE : lSize );
94 
95  if ( !s_pMPEGData ) {
96  printf ( "test_mpeg: could not allocate enough memory (%ld)\n", lSize );
97  goto end;
98  } /* end if */
99 
100  if ( read (
102  ) != lSize
103  ) {
104  printf ( "test_mpeg: could not read file\n" );
105  goto end;
106  } /* end if */
107 
108  close ( lFD );
109 
110 /* initialize DMAC (I have no idea what this code does as */
111 /* I'm not quite familiar with ps2sdk) */
115 
116 /* initialize graphics synthesizer */
117  graph_initialize(0,640,512,GS_PSM_32,0,0);
118 
119 /* setup texture buffer address just after the framebuffer */
121 
122  q = lPck->data;
123  q = draw_setup_environment(q,0,&frame,&z);
124 
125 /* clear screen */
126  q = draw_clear(q,0,0,0,640.0f,512.0f,0,0,0);
127 
128  dma_channel_send_normal(DMA_CHANNEL_GIF, lPck->data, q - lPck->data, 0, 0);
129 
130 /* now it's time to initialize MPEG decoder (though it can be */
131 /* initialized any time). Just make sure that DMA transfers */
132 /* to and from IPU (and DRAM -> SPR) are not active, otherwise */
133 /* unpredicted things will happen. Initialization code is also */
134 /* allocating some memory using 'memalign' function and no */
135 /* check is performed whether the allocation was successful or */
136 /* not, so, before calling this make sure that at least WxHx4x3 */
137 /* bytes are avaliable for dynamic allocation (possibly using */
138 /* ps2_sbrk ( 0 ) call) where W and H are picture dimensions in */
139 /* units of pixels. */
140  MPEG_Initialize ( SetDMA, NULL, InitCB, &lInfo, &lCurPTS );
141 /* during decoding scratchpad RAM from address 0x0000 to 0x3C00 */
142 /* is used by the decoder. */
143 /* let's go */
144  while ( 1 ) {
145 /* try decode picture into "lInfo.m_pData" area. It's allowed */
146 /* to supply different area each time, just make sure that */
147 /* there're no conflicts with data cache, as decoder doesn't do */
148 /* anything to synchronize/flush/invalidate data cache. */
149 /* RGB -> YUV colorspace conversion is pefromed automatically */
150 /* using interrupt hahdler/semaphore, so, multithreaded */
151 /* application can benefit from it. Usage of IPU and DMA channels */
152 /* to/from IPU and DRAM -> SPR is strictly forbidden during */
153 /* decoding :). */
154  if ( !MPEG_Picture ( lInfo.m_pData, &lPTS ) ) {
155 /* MPEG_Picture returns nonzero if the picture was successfully */
156 /* decoded. Zero return means one of the following: */
157 /* - end of stream was detected (SetDMA function returned zero) */
158 /* - MPEG sequence end code (0x000001B7) was detected */
159 /* this test just finishes in both cases */
160  if ( lInfo.m_pInfo -> m_fEOF ) break;
161 /* ...instead of 'break' we can continue to the next sequence...*/
162 /* ...but I'm too lazy to handle second call of 'InitCB' :D */
163  else break;
164  } /* end if */
165 /* now transfer decoded picture data into texture area of GS RAM */
166  dma_wait_fast();
167  dma_channel_send_chain( DMA_CHANNEL_GIF, lInfo.m_XFerPck -> data, lInfo.m_XFerPck -> qwc, 0, 0);
168 /* wait for vsync 2 times (we have interlaced frame mode) */
169  graph_wait_vsync ();
170  graph_wait_vsync ();
171 /* no need to wait for DMA transfer completion since vsyncs above */
172 /* have enough lattency... */
173 /* ...and finally draw decoded picture... */
174  dma_channel_send_normal( DMA_CHANNEL_GIF, lInfo.m_DrawPck -> data, lInfo.m_DrawPck -> qwc, 0, 0);
175 /* ...and go back for the next one */
176  } /* end while */
177 /* free memory and other resources */
178  MPEG_Destroy ();
179 
180 end:
181  printf ( "test_mpeg: test finished\n" );
182  return SleepThread (), 0;
183 
184 } /* end main */
185 /* This gets called by MPEG decoder to get data to decode. */
186 /* It performs normal DMA data transfer to IPU and returns */
187 /* nozero to indicate that data have been sent. Zero return */
188 /* indicates end-of-data condition, Amount of data per */
189 /* transfer doesn't really matter, but it must be less than */
190 /* 1MB minus 16. Sample function uses 2048 bytes blocks. */
191 /* Don't use source chain transfer as it will lead to */
192 /* unpredictable results. */
193 static int SetDMA ( void* apUserData ) {
194 
195  if ( s_pTransferPtr - s_pMPEGData >= s_MPEGDataSize ) return 0;
196 
199  DMA_CHANNEL_toIPU, s_pTransferPtr, 2048>>4, 0, 0
200  );
201  s_pTransferPtr += 2048;
202 
203  return 1;
204 
205 } /* end SetDMA */
206 
207 /* This gets called when sequence start header is detected in the */
208 /* input bitstream. <apInfo> is filled by the decoder and callback */
209 /* function initializes display process and other required stuff */
210 /* based upon values provided in <apInfo> stucture. It should return */
211 /* pointer to the data area where decoded picture (RGBA32, 16x16 */
212 /* blocks) will be stored. Pointer is supposed to be 16 byte aligned. */
213 /* It can be called several times (depending on number of video */
214 /* sequences inside a bitstream). It is allowed to return the same */
215 /* pointer each time, but the data area should be large enough to */
216 /* accomodate the whole picture. <apParam> is just a user supplied */
217 /* data (anything). */
218 static void* InitCB ( void* apParam, MPEGSequenceInfo* apInfo ) {
219 
220  int lDataSize = apInfo -> m_Width * apInfo -> m_Height * 4;
221  char* retVal = ( char* )malloc ( lDataSize );
222  InitCBParam* lpParam = ( InitCBParam* )apParam;
223  int lMBW = ( apInfo -> m_Width ) >> 4;
224  int lMBH = ( apInfo -> m_Height ) >> 4;
225  int lTBW = ( apInfo -> m_Width + 63 ) >> 6;
226  int lTW = draw_log2 ( apInfo -> m_Width );
227  int lTH = draw_log2 ( apInfo -> m_Height );
228  int lX, lY;
229  char* lpImg;
230  qword_t* q;
231 
232  lpParam -> m_TexAddr >>= 6;
233 
234  lpParam -> m_pData = lpImg = retVal;
235  lpParam -> m_pInfo = apInfo;
236  SyncDCache ( retVal, retVal + lDataSize );
237 /* This initializes picture transfer packet. */
238 /* Decoded picture is a sequence of 16x16 pixels */
239 /* 'subpictures' (macroblocks) and DMA controller */
240 /* will transfer them all at once using source */
241 /* chain transfer mode. */
242  lpParam -> m_XFerPck = packet_init((10 + 12 * lMBW * lMBH )>>1,PACKET_NORMAL);
243 
244  q = lpParam-> m_XFerPck -> data;
245 
246  DMATAG_CNT(q, 3, 0, 0, 0);
247  q++;
248  PACK_GIFTAG(q,GIF_SET_TAG( 2, 0, 0, 0, 0, 1 ),GIF_REG_AD);
249  q++;
251  q++;
252  PACK_GIFTAG(q,GS_SET_BITBLTBUF( 0, 0, 0, lpParam -> m_TexAddr, lTBW, GS_PSM_32 ), GS_REG_BITBLTBUF);
253  q++;
254 
255  for ( lY = 0; lY < apInfo -> m_Height; lY += 16 ) {
256  for ( lX = 0; lX < apInfo -> m_Width; lX += 16, lpImg += 1024 ) {
257  DMATAG_CNT(q, 4, 0, 0, 0 );
258  q++;
259  PACK_GIFTAG(q,GIF_SET_TAG( 2, 0, 0, 0, 0, 1 ), GIF_REG_AD );
260  q++;
261  PACK_GIFTAG(q,GS_SET_TRXPOS( 0, 0, lX, lY, 0 ), GS_REG_TRXPOS );
262  q++;
264  q++;
265  PACK_GIFTAG(q,GIF_SET_TAG( 64, 1, 0, 0, 2, 0),0);
266  q++;
267  DMATAG_REF(q, 64, ( unsigned )lpImg, 0, 0, 0);
268  q++;
269  } /* end for */
270  } /* end for */
271 
272  //DMATAG_END(q,0,0,0,0);
273  //q++;
274 
275  lpParam-> m_XFerPck -> qwc = q - lpParam-> m_XFerPck -> data;
276 
277 /* This initializes picture drawing packet. Just textrured sprite */
278 /* that occupies the whole screen (no aspect ratio is taken into */
279 /* account for simplicity. */
280  lpParam -> m_DrawPck = packet_init(7,PACKET_NORMAL);
281  q = lpParam -> m_DrawPck -> data;
282  PACK_GIFTAG(q, GIF_SET_TAG( 6, 1, 0, 0, 0, 1 ), GIF_REG_AD );
283  q++;
284  PACK_GIFTAG(q, GS_SET_TEX0( lpParam -> m_TexAddr, lTBW, GS_PSM_32, lTW, lTH, 1, 1, 0, 0, 0, 0, 0 ), GS_REG_TEX0_1 );
285  q++;
286  PACK_GIFTAG(q, GS_SET_PRIM( 6, 0, 1, 0, 0, 0, 1, 0, 0 ), GS_REG_PRIM );
287  q++;
288  PACK_GIFTAG(q, GS_SET_UV( 0, 0 ), GS_REG_UV );
289  q++;
290  PACK_GIFTAG(q, GS_SET_XYZ( 0, 0, 0 ), GS_REG_XYZ2 );
291  q++;
292  PACK_GIFTAG(q, GS_SET_UV( apInfo -> m_Width << 4, apInfo -> m_Height << 4 ), GS_REG_UV );
293  q++;
294  PACK_GIFTAG(q, GS_SET_XYZ( (640 << 4) + (2048 << 4), (512 << 4) + (2048 << 4), 0 ), GS_REG_XYZ2 );
295  q++;
296 
297  lpParam -> m_DrawPck -> qwc = q - lpParam -> m_DrawPck -> data;
298 
299  return retVal;
300 
301 } /* end InitCB */
void dma_wait_fast(void)
Definition: dma.c:115
int dma_channel_send_normal(int channel, void *data, int qwc, int flags, int spr)
Definition: dma.c:238
#define DMA_CHANNEL_toIPU
Definition: dma.h:26
int dma_channel_wait(int channel, int timeout)
Definition: dma.c:130
int dma_channel_initialize(int channel, void *handler, int flags)
Definition: dma.c:58
#define DMA_CHANNEL_GIF
Definition: dma.h:24
void dma_channel_fast_waits(int channel)
Definition: dma.c:108
int dma_channel_send_chain(int channel, void *data, int qwc, int flags, int spr)
Definition: dma.c:184
#define DMATAG_REF(Q, QWC, ADDR, SPR, W2, W3)
Definition: dma_tags.h:93
#define DMATAG_CNT(Q, QWC, SPR, W2, W3)
Definition: dma_tags.h:57
qword_t * draw_setup_environment(qword_t *q, int context, framebuffer_t *frame, zbuffer_t *z)
Definition: draw.c:11
qword_t * draw_clear(qword_t *q, int context, float x, float y, float width, float height, int r, int g, int b)
Definition: draw.c:148
unsigned char draw_log2(unsigned int x)
Definition: draw.c:348
#define PACK_GIFTAG(Q, D0, D1)
Definition: gif_tags.h:76
#define GIF_SET_TAG(NLOOP, EOP, PRE, PRIM, FLG, NREG)
Definition: gif_tags.h:80
#define GIF_REG_AD
Definition: gif_tags.h:72
int graph_initialize(int fbp, int width, int height, int psm, int x, int y)
Definition: graph.c:6
void graph_wait_vsync(void)
Definition: graph.c:99
#define GRAPH_ALIGN_BLOCK
Definition: graph_vram.h:16
int graph_vram_allocate(int width, int height, int psm, int alignment)
Definition: graph_vram.c:7
#define GRAPH_ALIGN_PAGE
Definition: graph_vram.h:13
#define GS_REG_TEX0_1
Definition: gs_gp.h:27
#define GS_SET_XYZ(X, Y, Z)
Definition: gs_gp.h:326
#define GS_SET_TRXREG(W, H)
Definition: gs_gp.h:317
#define GS_REG_TRXREG
Definition: gs_gp.h:135
#define GS_SET_PRIM(PRIM, IIP, TME, FGE, ABE, AA1, FST, CTXT, FIX)
Definition: gs_gp.h:237
#define GS_SET_BITBLTBUF(SBA, SBW, SPSM, DBA, DBW, DPSM)
Definition: gs_gp.h:175
#define GS_SET_TRXPOS(SX, SY, DX, DY, DIR)
Definition: gs_gp.h:312
#define GS_SET_TEX0(TBA, TBW, PSM, TW, TH, TCC, TFNCT, CBA, CPSM, CSM, CSA, CLD)
Definition: gs_gp.h:281
#define GS_REG_PRIM
Definition: gs_gp.h:13
#define GS_REG_XYZ2
Definition: gs_gp.h:23
#define GS_REG_UV
Definition: gs_gp.h:19
#define GS_REG_TRXPOS
Definition: gs_gp.h:133
#define GS_REG_BITBLTBUF
Definition: gs_gp.h:131
#define GS_SET_UV(U, V)
Definition: gs_gp.h:320
#define GS_REG_TRXDIR
Definition: gs_gp.h:137
#define GS_SET_TRXDIR(DIR)
Definition: gs_gp.h:308
#define GS_PSM_32
Definition: gs_psm.h:11
void SyncDCache(void *start, void *end)
s32 SleepThread(void)
u32 data
Definition: libmouse.c:36
void MPEG_Destroy(void)
Definition: libmpeg.c:117
int(* MPEG_Picture)(void *, s64 *)
Definition: libmpeg.h:62
void MPEG_Initialize(int(*)(void *), void *, void *(*)(void *, MPEGSequenceInfo *), void *, s64 *)
#define MAX_SIZE
Definition: mpeg.c:36
static unsigned char * s_pTransferPtr
Definition: mpeg.c:49
static int SetDMA(void *)
Definition: mpeg.c:193
static void * InitCB(void *, MPEGSequenceInfo *)
Definition: mpeg.c:218
int main(void)
Definition: mpeg.c:55
static unsigned char * s_pMPEGData
Definition: mpeg.c:48
#define MPEG_BITSTREAM_FILE
Definition: mpeg.c:34
static unsigned int s_MPEGDataSize
Definition: mpeg.c:50
packet_t * packet_init(int qwords, int type)
Definition: packet.c:8
#define PACKET_NORMAL
Definition: packet.h:14
int m_TexAddr
Definition: mpeg.c:44
MPEGSequenceInfo * m_pInfo
Definition: mpeg.c:40
packet_t * m_DrawPck
Definition: mpeg.c:43
packet_t * m_XFerPck
Definition: mpeg.c:42
void * m_pData
Definition: mpeg.c:41
unsigned int address
Definition: draw_buffers.h:41
unsigned int height
Definition: draw_buffers.h:43
unsigned int psm
Definition: draw_buffers.h:44
unsigned int mask
Definition: draw_buffers.h:45
unsigned int width
Definition: draw_buffers.h:42
qword_t * data
Definition: packet.h:27
unsigned int mask
Definition: draw_buffers.h:53
unsigned int method
Definition: draw_buffers.h:50
unsigned int address
Definition: draw_buffers.h:51
unsigned int enable
Definition: draw_buffers.h:49
unsigned int zsm
Definition: draw_buffers.h:52
#define NULL
Definition: tamtypes.h:91
signed long s64
Definition: tamtypes.h:62