[MPlayer-dev-eng] Supporting em84xx as output device - Done !

Helmut Auer vdr at helmutauer.de
Sun Oct 22 11:32:37 CEST 2006


Hi List,

It's done :)
With the attached Patch ( must be used after configure ) mplayer-1.0pre8 will be able to use the 
em84xx decoder for playback. You need the sigma sdk to  compile it ( fmp.h ) and the library 
libEM84xx.so for linking.

-- 
Helmut Auer, helmut at helmutauer.de

diff -uN -x '*.o' -x '*.a' libao2/ao_em84xx.c libao2/ao_em84xx.c
--- libao2/ao_em84xx.c  1970-01-01 01:00:00.000000000 +0100
+++ libao2/ao_em84xx.c  2006-10-16 15:26:55.000000000 +0200
@@ -0,0 +1,166 @@
+/*
+ * Based on: ao_em84xx.c
+ *
+ * ao_em84.c - audio out to vdr-file
+ *
+ * Copyright (C) 2006 Helmut Auer & Uwe Scheffler
+ *
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include <errno.h>
+
+#include "audio_out.h"
+#include "audio_out_internal.h"
+
+#include "libaf/af_format.h"
+
+#define _DEFINE_FMP_TYPES_
+#define _BARBADOS_
+#include <fmp.h>
+
+extern int vo_vdr_fd;
+
+int em84Volume[2]={50,50};
+
+static ao_info_t info =
+{
+   "Mpeg-PES audio output to em84 or vdr-file",
+   "em84xx",
+   "HelAu",
+   ""
+};
+
+LIBAO_EXTERN(em84xx)
+
+// to set/get/query special features/parameters
+static int control(int cmd,void *arg)
+{
+   if(vo_vdr_fd < 0) {
+      switch(cmd){
+         case AOCONTROL_GET_VOLUME:
+            ((ao_control_vol_t*)(arg))->left=em84Volume[0];
+            ((ao_control_vol_t*)(arg))->right=em84Volume[1];
+            mp_msg(MSGT_AO,MSGL_V, "EM84 Get_Volume(%d-%d)\n", em84Volume[0],em84Volume[1]);
+            return CONTROL_OK;
+         case AOCONTROL_SET_VOLUME:
+            em84Volume[0]=((ao_control_vol_t*)(arg))->left;
+            em84Volume[1]=((ao_control_vol_t*)(arg))->right;
+            mp_msg(MSGT_AO,MSGL_V, "EM84 Set_Volume(%d-%d)\n", em84Volume[0],em84Volume[1]);
+            FMPSet(FMPI_LEFT_VOLUME,em84Volume[0]);
+            FMPSet(FMPI_RIGHT_VOLUME,em84Volume[1]);
+            return CONTROL_OK;
+      }
+   }
+   return CONTROL_UNKNOWN;
+}
+
+static int freq=0;
+static int freq_id=0;
+
+// open & setup audio device
+// return: 1=success 0=fail
+static int init(int rate,int channels,int format,int flags)
+{
+   ao_data.channels=2;
+   ao_data.outburst=2000;
+   switch( format ) {
+      case AF_FORMAT_S16_LE:
+      case AF_FORMAT_S16_BE:
+      case AF_FORMAT_MPEG2:
+      case AF_FORMAT_AC3:
+         ao_data.format=format;
+         break;
+      default:
+         ao_data.format=AF_FORMAT_S16_BE;
+   }
+
+   switch( rate ) {
+      case 48000: freq_id=0;break;
+      case 96000: freq_id=1;break;
+      case 44100: freq_id=2;break;
+      case 32000: freq_id=3;break;
+      default:
+         mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_MPEGPES_UnsupSamplerate, rate);
+         rate=48000; freq_id=0;
+   }
+
+   ao_data.bps=rate*2*2;
+   freq=ao_data.samplerate=rate;
+
+   if(vo_vdr_fd < 0) {
+      FMPSet(FMPI_LEFT_VOLUME,em84Volume[0]);
+      FMPSet(FMPI_RIGHT_VOLUME,em84Volume[1]);
+   }
+
+   return 1;
+}
+
+// close audio device
+static void uninit(int immed)
+{
+}
+
+// stop playing and empty buffers (for seeking/pause)
+static void reset(void)
+{
+}
+
+// stop playing, keep buffers (for pause)
+static void audio_pause(void)
+{
+   // for now, just call reset();
+   reset();
+}
+
+// resume playing, after audio_pause()
+static void audio_resume(void)
+{
+}
+
+void send_em84_pes_packet(unsigned char* data,int len,int id,int timestamp);
+void send_em84_lpcm_packet(unsigned char* data,int len,int id,int timestamp,int freq_id);
+extern int vo_pts;
+
+// return: how many bytes can be played without blocking
+static int get_space(void)
+{
+   float x=(float)(vo_pts-ao_data.pts)/90000.0;
+   int y;
+//   printf("vo_pts: %5.3f  ao_pts: %5.3f\n",vo_pts/90000.0,ao_data.pts/90000.0);
+   if( x<=0 ) return 0;
+   y=freq*4*x;y/=ao_data.outburst;y*=ao_data.outburst;
+   if( y>32000 ) y=32000;
+//    printf("diff: %5.3f -> %d  \n",x,y);
+   return y;
+}
+
+// plays 'len' bytes of 'data'
+// it should round it down to outburst*n
+// return: number of bytes played
+static int play(void* data,int len,int flags)
+{
+   mp_msg(MSGT_AO,MSGL_V, "ao_vdr: play(%d) freq=%d\n",len,freq_id);
+   if( ao_data.format==AF_FORMAT_MPEG2 )
+      send_em84_pes_packet(data,len,0x1C0,ao_data.pts);
+   else {
+      int i;
+      unsigned short *s=data;
+      if( ao_data.format==AF_FORMAT_S16_LE || ao_data.format==AF_FORMAT_AC3 )
+         for( i=0;i<len/2;i++ ) s[i]=(s[i]>>8)|(s[i]<<8); // le<->be
+      send_em84_lpcm_packet(data,len,0xA0,ao_data.pts,freq_id);
+   }
+   return len;
+}
+
+// return: delay in seconds between first and last sample in buffer
+static float get_delay(void)
+{
+   return 0.0;
+}
diff -uN -x '*.o' -x '*.a' libao2/audio_out.c libao2/audio_out.c
--- libao2/audio_out.c  2006-06-11 20:35:42.000000000 +0200
+++ libao2/audio_out.c  2006-10-04 13:40:42.000000000 +0200
@@ -66,6 +66,7 @@
  extern ao_functions_t audio_out_dxr2;
  #endif
  extern ao_functions_t audio_out_mpegpes;
+extern ao_functions_t audio_out_em84xx;
  extern ao_functions_t audio_out_pcm;
  extern ao_functions_t audio_out_pss;

@@ -73,6 +74,7 @@
  {
  // vo-related:   will fail unless you also do -vo mpegpes/dxr2
         &audio_out_mpegpes,
+    &audio_out_em84xx,
  #ifdef HAVE_DXR2
          &audio_out_dxr2,
  #endif
diff -uN -x '*.o' -x '*.a' libao2/Makefile libao2/Makefile
--- libao2/Makefile     2006-06-11 20:35:42.000000000 +0200
+++ libao2/Makefile     2006-10-04 13:41:12.000000000 +0200
@@ -4,6 +4,7 @@

  SRCS=audio_out.c \
       ao_mpegpes.c \
+     ao_em84xx.c \
       ao_null.c \
       ao_pcm.c \
       $(OPTIONAL_SRCS) \
--- etc/codecs.conf     2006-06-11 20:35:46.000000000 +0200
+++ etc/codecs.conf     2006-10-04 13:39:50.000000000 +0200
@@ -43,6 +43,15 @@
    driver mpegpes
    out MPES

+videocodec em84xx
+  info "EM84xx (em84 decoder)"
+  comment "for hardware decoding"
+  status working
+  format 0x10000001  ; mpeg 1
+  format 0x10000002  ; mpeg 2
+  driver em84xx
+  out MPES
+
  videocodec mpeg12
    info "MPEG-1 or 2 (libmpeg2)"
    comment "with postprocessing"
--- Makefile    2006-06-11 20:35:47.000000000 +0200
+++ Makefile    2006-10-04 14:33:56.000000000 +0200
@@ -74,6 +74,7 @@
            $(DIRECTFB_LIB) \
            $(CACA_LIB) \
           $(VESA_LIB) \
+         -lEM84xx \

  ifeq ($(EXTERNAL_VIDIX),yes)
  VO_LIBS += $(EXTERNAL_VIDIX_LIB)
diff -uN -x '*.o' -x '*.a' libvo/Makefile libvo/Makefile
--- libvo/Makefile      2006-06-11 20:35:43.000000000 +0200
+++ libvo/Makefile      2006-10-04 13:41:27.000000000 +0200
@@ -13,6 +13,7 @@
       sub.c \
       video_out.c \
       vo_mpegpes.c \
+     vo_em84xx.c \
       vo_null.c \
       vo_yuv4mpeg.c \
       $(OPTIONAL_SRCS) \
diff -uN -x '*.o' -x '*.a' libvo/video_out.c libvo/video_out.c
--- libvo/video_out.c   2006-06-11 20:35:43.000000000 +0200
+++ libvo/video_out.c   2006-10-04 13:40:56.000000000 +0200
@@ -92,6 +92,7 @@
  extern vo_functions_t video_out_aa;
  extern vo_functions_t video_out_caca;
  extern vo_functions_t video_out_mpegpes;
+extern vo_functions_t video_out_em84xx;
  extern vo_functions_t video_out_yuv4mpeg;
  #ifdef HAVE_DIRECTX
  extern vo_functions_t video_out_directx;
@@ -242,6 +243,7 @@
          &video_out_xvmc,
  #endif
         &video_out_mpegpes,
+    &video_out_em84xx,
         &video_out_yuv4mpeg,
  #ifdef HAVE_PNG
         &video_out_png,
diff -uN -x '*.o' -x '*.a' libvo/vo_em84xx.c libvo/vo_em84xx.c
--- libvo/vo_em84xx.c   1970-01-01 01:00:00.000000000 +0100
+++ libvo/vo_em84xx.c   2006-10-16 15:26:20.000000000 +0200
@@ -0,0 +1,504 @@
+/*
+ * Based on: vo_mpegpes.c
+ *
+ * vo_em84xx.c - video out to em84xx decoder
+ *
+ * Copyright (C) 2006 Helmut Auer & Uwe Scheffler
+ *
+ */
+#define KILOBYTE(n) ((n) * 1024)
+#define _DEFINE_FMP_TYPES_
+#define _BARBADOS_
+
+#include <fmp.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+
+#define PES_EM_MAX_SIZE KILOBYTE(32)
+#define PES_FILE_MAX_SIZE KILOBYTE(32)
+
+#define PES_HEADER_MAX_LEN 32 // a little bit more than needed :)
+
+#include "mp_msg.h"
+#include "aspect.h"
+#include "video_out.h"
+#include "video_out_internal.h"
+
+#define VDR_FILE_MAX_LEN 2000000000
+#define VDR_DEF_NAME "/video/001.vdr"
+
+extern float monitor_aspect;
+extern float movie_aspect;
+static int so_width=0, so_height=0;
+int mdelay=0;
+int mLastAspect=0;
+int mSourceAspect = 0;
+
+int SetAudioSampleRate=48000;
+int mLastSetAudioSampleRate=0;
+
+int vo_vdr_fd = -1;
+static int vdrFileLen = 0;
+
+static char vdrFileName[1024] = "";
+
+static vo_info_t info =
+{
+   "Mpeg-PES video to EM84 or file",
+   "em84xx",
+   "HelAu",
+   ""
+};
+
+LIBVO_EXTERN (em84xx)
+
+static int
+config(uint32_t s_width, uint32_t s_height, uint32_t width, uint32_t height, uint32_t flags, 
char *title, uint32_t format)
+{
+   switch( s_height ) {
+      case 288:
+      case 576:
+      case 240:
+      case 480:
+         break;
+      default:
+         mp_msg(MSGT_VO,MSGL_ERR,"EM84: height=%d not supported (try 240/480 (ntsc) or 288/576 
(pal)\n",s_height);
+         return -1;
+   }
+
+   return 0;
+}
+
+static int preinit(const char *arg)
+{
+   DWORD PropVal, PropValSize, rc;
+
+   if( arg ) {
+      strcpy( vdrFileName, arg );
+
+      vo_vdr_fd=open(vdrFileName,O_WRONLY|O_CREAT|O_TRUNC,0666);
+      if(vo_vdr_fd<0){
+         mp_msg(MSGT_VO,MSGL_ERR, "Error opening <%s>\n", vdrFileName);
+         return -1;
+      }
+      mp_msg(MSGT_VO,MSGL_INFO, "Saving PES stream to %s\n", vdrFileName);
+//      mp_msg(MSGT_VO,MSGL_V, "Saving PES stream to %s\n", vdrFileName);
+   }
+   else {
+      MPEGDriverEntry(NO_DRIVE);
+      if( (rc = FMPOpen(FMPF_PROGRAM, PES_EM_MAX_SIZE, 10, NULL, 0)) != FMPE_OK ) {
+         mp_msg(MSGT_VO,MSGL_ERR,"EM84: FMPOpen Error: %x\n",rc);
+         return -1;
+      }
+
+      Wnd_type dest_wnd;
+      dest_wnd.x = 0;
+      dest_wnd.y = 0;
+      dest_wnd.w = 720;
+      dest_wnd.h = 576;
+
+      DWORD sizeOut = 0;
+      DWORD doHwReset = 0;
+      DWORD disableSpdifOndoHwReset = 0;
+      eAudioDigitalOutput_type spdifMode = eAudioDigitalOutput_Pcm;
+
+      DWORD tvOut = SET_TV | SET_PAL;// | 0x10;// | SET_ONETOONE;// | SET_TV_AS_USER;
+
+      FMPProperty (KSPROPERTY_TYPE_SET, REGISTRY_COMMON_SET, eTvOut, 0, &tvOut, sizeof(tvOut ), 
&sizeOut);
+      FMPProperty (KSPROPERTY_TYPE_SET, REGISTRY_COMMON_SET, eDoHwReset, 0, &doHwReset, 
sizeof(doHwReset), &sizeOut);
+      FMPProperty (KSPROPERTY_TYPE_SET, REGISTRY_COMMON_SET, eDisableSpdifOutputInReset , 0, 
&disableSpdifOndoHwReset , sizeof(disableSpdifOndoHwReset ), &sizeOut); // not needed, but you 
never now :)
+//      FMPProperty (KSPROPERTY_TYPE_SET, AUDIO_SET, eAudioDigitalOutput, 0, &spdifMode, 
sizeof(eAudioDigitalOutput_type), &sizeOut);
+      FMPProperty (KSPROPERTY_TYPE_SET, VIDEO_SET, evDestinationWindow, 0, &dest_wnd, 
sizeof(Wnd_type), &sizeOut);
+
+      // this line is necc, so that 16x9 switching works even after setting the video dest. 
window from above
+      FMPSet(FMPI_OVERLAY_FLAGS, OSD_VIDEO_INDEPENDENT_DEST);
+
+      // Disable 16 bit VMI (at least by 6086N2 doesn't like this, YMMV again)
+      PropVal=0;
+ 
FMPProperty(KSPROPERTY_TYPE_SET,REGISTRY_VGAVENDOR_SET,eVmi_16bits,0,&PropVal,sizeof(PropVal),&PropValSize);
+
+      eAudioFormat_type audioformat = eAudioFormat_PCM;
+      FMPProperty (KSPROPERTY_TYPE_SET, AUDIO_SET, eAudioFormat, 0, &audioformat, 
sizeof(eAudioFormat_type), &sizeOut);
+
+      FMPSet(FMPI_VIDEOOUT, FMPV_VIDEOOUT_COMPOSITE | FMPV_VIDEOOUT_TV |
+             FMPV_VIDEOOUT_PAL);
+
+   //          SetVideoFormat(Setup.VideoFormat);
+      FMPSetVideoPortDimensions(720, 576);
+
+      FMPPlay();
+   }
+
+   return 0;
+}
+
+
+static void draw_osd(void)
+{
+}
+
+
+static void my_write(unsigned char* header,int headerLen, unsigned char* data,int dataLen, int 
streamType)
+{
+   FMP_BUFFER fmpBuf;
+   DWORD rc;
+   DWORD flags = 0;
+//   static int count=0;
+
+
+   if(vo_vdr_fd<0){
+      if ( dataLen > 0 && ( dataLen + headerLen ) <= PES_EM_MAX_SIZE ) {
+         fmpBuf.dwFlagsEx = streamType;
+         if( (rc = FMPGetBuffer(&fmpBuf, TRUE)) != FMPE_OK ) {
+            mp_msg(MSGT_VO,MSGL_ERR,"[mplayer] Couldn't allocate em8400 replaybuffer: %lx\n", rc);
+            return;
+         }
+
+         memcpy( fmpBuf.pBuffer, header, headerLen );
+         memcpy( fmpBuf.pBuffer + headerLen, data, dataLen );
+
+         fmpBuf.dwDataSize = headerLen + dataLen;
+
+         if( (rc = FMPPush(&fmpBuf)) != FMPE_OK ) {
+            mp_msg(MSGT_VO,MSGL_ERR,"EM84: FMPPush Error: %x\n",rc);
+         }
+      }
+      else
+         mp_msg(MSGT_VO,MSGL_ERR,"EM84: my_write invalid length: %d-%d\n",headerLen,dataLen);
+   }
+   else {
+      if( vdrFileLen + headerLen + dataLen > VDR_FILE_MAX_LEN ) {
+         close(vo_vdr_fd);
+         vdrFileLen = 0;
+         if(vdrFileName[strlen(vdrFileName)-1] == '9') {
+            (vdrFileName[strlen(vdrFileName)-1]) = '0';
+            if(vdrFileName[strlen(vdrFileName)-2] == '9') {
+               (vdrFileName[strlen(vdrFileName)-2]) = '0';
+               (vdrFileName[strlen(vdrFileName)-3])++;
+            }
+            else
+               (vdrFileName[strlen(vdrFileName)-2])++;
+         }
+         else
+            (vdrFileName[strlen(vdrFileName)-1])++;
+
+         vo_vdr_fd=open(vdrFileName,O_WRONLY|O_CREAT,0666);
+         if(vo_vdr_fd<0)
+            mp_msg(MSGT_VO,MSGL_ERR, "Error opening <%s>\n", vdrFileName);
+         else
+            mp_msg(MSGT_VO,MSGL_INFO, "Saving PES stream to %s\n", vdrFileName);
+      }
+
+         if(vo_vdr_fd>=0){
+          write(vo_vdr_fd,header,headerLen); // write to file
+          write(vo_vdr_fd,data,dataLen); // write to file
+          usleep(0);
+          vdrFileLen += headerLen + dataLen;
+         }
+
+   }
+}
+
+
+void send_em84_pes_packet(unsigned char* data,int len,int id,int timestamp)
+{
+
+       int pos = 0;
+       int esLength = 0;
+
+
+       if (!data[pos] && !data[pos+1] && data[pos+2] == 0x01 && (data[pos+3] == 0xB3 ))
+       {
+
+               mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] switch: %d \n",((data[pos + 7]) & 0xF0) );
+                switch ((data[pos + 7]) & 0xF0)
+               {
+
+                   case 0x20:
+                               mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] (case 0x20) FMPV_VIDEOASPECT 
--> 4x3 \n");
+                               mSourceAspect=43;
+                        break;
+
+                    case 0x30:
+                               mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] (case 0x30) FMPV_VIDEOASPECT 
--> 16x9 \n");
+                               mSourceAspect=169;
+                        break;
+
+                    default:
+                               mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] (default) FMPV_VIDEOASPECT 
--> NORMAL \n");
+                               mSourceAspect=1;
+                        break;
+
+               }
+
+
+
+    if (mLastAspect != mSourceAspect && mSourceAspect != 0)
+    {
+
+        // Aspect ratio
+         if (mSourceAspect == 169) {
+           //Source 16:9
+           mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] source aspect ratio 16:9\n");
+           if (1.76 <= monitor_aspect && monitor_aspect <=1.80) {
+               //OUTPUT 16:9
+                   FMPSet(FMPI_VIDEOASPECT, FMPV_VIDEOASPECT_16x9_16x9_NORMAL);
+                   mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] monitor aspect ratio 16:9\n");
+                 } else {
+                   FMPSet(FMPI_VIDEOASPECT,  FMPV_VIDEOASPECT_16x9_4x3_LETTERBOX);
+                   mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] monitor aspect ratio 4:3\n");
+                 }
+         }
+         if (mSourceAspect == 43) {
+           //Source 4:3
+           mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] source aspect ratio 4:3\n");
+           if (1.76 <= monitor_aspect && monitor_aspect <=1.80) {
+               //OUTPUT 16:9
+                   FMPSet(FMPI_VIDEOASPECT,  FMPV_VIDEOASPECT_4x3_16x9_ZOOM_OFF);
+                   mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] monitor aspect ratio 16:9\n");
+                 } else {
+                   FMPSet(FMPI_VIDEOASPECT,  FMPV_VIDEOASPECT_4x3_4x3_NORMAL);
+                   mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] monitor aspect ratio 4:3\n");
+                 }
+           }
+         if (mSourceAspect == 1) {
+           //Source 1:1
+           mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] source aspect ratio 1:1\n");
+           if (1.76 <= monitor_aspect && monitor_aspect <=1.80) {
+               //OUTPUT 16:9
+                   FMPSet(FMPI_VIDEOASPECT,  FMPV_VIDEOASPECT_16x9_16x9_NORMAL);
+                   mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] monitor aspect ratio 16:9\n");
+                 } else {
+                   FMPSet(FMPI_VIDEOASPECT,  FMPV_VIDEOASPECT_4x3_4x3_NORMAL);
+                   mp_msg(MSGT_VO,MSGL_V,"VO: [em84xx] monitor aspect ratio 4:3\n");
+                   }
+               }
+    if (mdelay >= 2)
+       {
+       mLastAspect = mSourceAspect;
+       mdelay = 0;
+       }else
+       mdelay +=1;
+    }
+  }
+
+
+   unsigned char pes_header[PES_HEADER_MAX_LEN];
+   int ptslen=timestamp?5:1;
+   int pesMaxLen = ( vo_vdr_fd >= 0 ) ? PES_FILE_MAX_SIZE : PES_EM_MAX_SIZE;
+   int payload_size;
+
+   mp_msg(MSGT_VO,MSGL_V, "Sending PES pts=%x size=%d\n",timestamp,len);
+
+   // startcode:
+   pes_header[0]=pes_header[1]=0;
+   pes_header[2]=id>>8; pes_header[3]=id&255;
+
+   while( len>0 ) {
+      if( 6+ptslen+len > pesMaxLen )
+         payload_size=pesMaxLen-(6+ptslen);
+      else
+         payload_size=len;  // data + PTS
+
+      // construct PES header:  (code from ffmpeg's libav)
+      // packetsize:
+      pes_header[4]=(ptslen+payload_size)>>8;
+      pes_header[5]=(ptslen+payload_size)&255;
+
+      if( ptslen==5 ) {
+         int x;
+         // presentation time stamp:
+         x=(0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1;
+         pes_header[6]=x;
+         x=((((timestamp >> 15) & 0x7fff) << 1) | 1);
+         pes_header[7]=x>>8; pes_header[8]=x&255;
+         x=((((timestamp) & 0x7fff) << 1) | 1);
+         pes_header[9]=x>>8; pes_header[10]=x&255;
+      }
+      else {
+         // stuffing and header bits:
+         pes_header[6]=0x0f;
+      }
+
+      my_write(pes_header,6+ptslen,data,payload_size, FMP_VIDEO_PES);
+
+      len-=payload_size; data+=payload_size;
+      ptslen=1; // store PTS only once, at first packet!
+   }
+}
+
+
+void send_em84_lpcm_packet(unsigned char* data,int len,int id,unsigned int timestamp,int freq_id)
+{
+
+       switch (freq_id)
+               {
+               case 0:
+                       SetAudioSampleRate=48000;
+                       break;
+
+               case 1:
+                       SetAudioSampleRate=96000;
+                       break;
+
+               case 2:
+                       SetAudioSampleRate=44100;
+                       break;
+
+               case 3:
+                       SetAudioSampleRate=32000;
+                       break;
+
+               default:
+                       break;
+               }
+
+ if (SetAudioSampleRate != mLastSetAudioSampleRate)
+ {
+       mLastSetAudioSampleRate = SetAudioSampleRate;
+
+       DWORD sizeOut;
+       FMPProperty (KSPROPERTY_TYPE_SET, AUDIO_SET, eAudioSampleRate, 0, 
&mLastSetAudioSampleRate, sizeof(mLastSetAudioSampleRate), &sizeOut);
+
+       int newSampleFactor = (int)(((float)mLastSetAudioSampleRate/48000.0)*1000.0);
+       FMPSet(FMPI_AUDIO_SPEED, newSampleFactor);
+       mp_msg(MSGT_VO,MSGL_INFO,"VO: [em84xx] SetAudioSampleRate:%d   newSampleFactor:%d \n", 
SetAudioSampleRate, newSampleFactor);
+ }
+
+
+   unsigned char pes_header[PES_HEADER_MAX_LEN];
+   int payload_size;
+   int ptslen=timestamp?5:0;
+   int pesMaxLen = ( vo_vdr_fd >= 0 ) ? PES_FILE_MAX_SIZE : PES_EM_MAX_SIZE;
+
+   mp_msg(MSGT_VO,MSGL_V, "Sending LPCM pts=%x size=%d\n",timestamp,len);
+
+   // startcode:
+   pes_header[0]=pes_header[1]=0;
+   pes_header[2]=1; pes_header[3]=0xA0;//0xA0
+
+   while( len>=4 ) {
+      if( 16+ptslen+len > pesMaxLen )
+         payload_size=pesMaxLen-(16+ptslen);
+      else
+         payload_size=len;  // data + PTS
+
+      payload_size&=(~3); // align!
+
+      // packetsize:
+      pes_header[4]=(payload_size+3+ptslen+7)>>8;
+      pes_header[5]=(payload_size+3+ptslen+7)&255;
+
+      // stuffing:
+      // TTCCxxxx  CC=css TT=type: 1=STD 0=mpeg1 2=vob
+      pes_header[6]=0x81;
+
+      // FFxxxxxx   FF=pts flags=2 vs 0
+      pes_header[7]=ptslen ? 0x80 : 0;
+
+      // hdrlen:
+      pes_header[8]=ptslen;
+
+      if( ptslen ) {
+         int x;
+         // presentation time stamp:
+         x=(0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1;
+         pes_header[9]=x;
+         x=((((timestamp >> 15) & 0x7fff) << 1) | 1);
+         pes_header[10]=x>>8; pes_header[11]=x&255;
+         x=((((timestamp) & 0x7fff) << 1) | 1);
+         pes_header[12]=x>>8; pes_header[13]=x&255;
+      }
+
+// ============ LPCM header: (7 bytes) =================
+// Info by mocm at convergence.de
+
+//        ID:
+      pes_header[ptslen+9]=id;
+//           pes_header[ptslen+9]=MM_AUDIO_FORMAT_PCM;
+
+//        number of frames:
+      pes_header[ptslen+10]=0x07;
+
+//        first acces unit pointer, i.e. start of audio frame:
+      pes_header[ptslen+11]=0x00;
+      pes_header[ptslen+12]=0x04;
+
+//        audio emphasis on-off                                  1 bit
+//        audio mute on-off                                      1 bit
+//        reserved                                               1 bit
+//        audio frame number                                     5 bit
+      pes_header[ptslen+13]=0x0C;
+
+//        quantization word length                               2 bit
+//        audio sampling frequency (48khz = 0, 96khz = 1)        2 bit
+//        reserved                                               1 bit
+//        number of audio channels - 1 (e.g. stereo = 1)         3 bit
+      pes_header[ptslen+14]=1;//|(freq_id<<4);
+
+//        dynamic range control (0x80 if off)
+      pes_header[ptslen+15]=0x80;
+
+      my_write(pes_header,16+ptslen,data,payload_size, FMP_AUDIO_PES);
+
+      len-=payload_size;
+      data+=payload_size;
+      ptslen=0; // store PTS only once, at first packet!
+   }
+}
+
+
+static int draw_frame(uint8_t * src[])
+{
+   vo_mpegpes_t *p=(vo_mpegpes_t *)src[0];
+   send_em84_pes_packet(p->data,p->size,p->id,(p->timestamp>0)?p->timestamp:vo_pts);  // video data
+   return 0;
+}
+
+static void flip_page (void)
+{
+}
+
+static int draw_slice(uint8_t *srcimg[], int stride[], int w,int h,int x0,int y0)
+{
+   return 0;
+}
+
+
+static int query_format(uint32_t format)
+{
+   if( format==IMGFMT_MPEGPES )
+      return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW|VFCAP_TIMER;
+
+   return 0;
+}
+
+static void uninit(void)
+{
+   if(vo_vdr_fd<0){
+      FMPStop();
+      FMPClose();
+      MPEGDriverUnload();
+   }
+   else
+      close( vo_vdr_fd );
+}
+
+
+static void check_events(void)
+{
+}
+
+static int control(uint32_t request, void *data, ...)
+{
+    mp_msg(MSGT_VO,MSGL_V, "control() request: %d\n", request);
+   switch( request ) {
+      case VOCTRL_QUERY_FORMAT:
+
+    return query_format(*((uint32_t*)data));
+   }
+
+   return VO_NOTIMPL;
+}
+



More information about the MPlayer-dev-eng mailing list