realvideo.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:17k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * realvideo.c: a realvideo decoder that uses the real's dll
  3.  *****************************************************************************
  4.  * Copyright (C) 2005 the VideoLAN team
  5.  * Copyright (C) 2008 Wang Bo
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  20.  *****************************************************************************/
  21. /*****************************************************************************
  22.  * Preamble
  23.  *****************************************************************************/
  24. #ifdef HAVE_CONFIG_H
  25. # include "config.h"
  26. #endif
  27. #include <vlc_common.h>
  28. #include <vlc_plugin.h>
  29. #include <vlc_vout.h>
  30. #include <vlc_codec.h>
  31. #ifdef LOADER
  32. /* Need the w32dll loader from mplayer */
  33. #   include <wine/winerror.h>
  34. #   include <ldt_keeper.h>
  35. #   include <wine/windef.h>
  36. void *WINAPI LoadLibraryA( char *name );
  37. void *WINAPI GetProcAddress( void *handle, char *func );
  38. int WINAPI FreeLibrary( void *handle );
  39. #endif
  40. #ifndef WINAPI
  41. #   define WINAPI
  42. #endif
  43. #if defined(HAVE_DL_DLOPEN)
  44. #   if defined(HAVE_DLFCN_H) /* Linux, BSD, Hurd */
  45. #       include <dlfcn.h>
  46. #   endif
  47. #   if defined(HAVE_SYS_DL_H)
  48. #       include <sys/dl.h>
  49. #   endif
  50. #endif
  51. typedef struct cmsg_data_s
  52. {
  53.     uint32_t data1;
  54.     uint32_t data2;
  55.     uint32_t* dimensions;
  56. } cmsg_data_t;
  57. typedef struct transform_in_s
  58. {
  59.     uint32_t len;
  60.     uint32_t unknown1;
  61.     uint32_t chunks;
  62.     uint32_t* extra;
  63.     uint32_t unknown2;
  64.     uint32_t timestamp;
  65. } transform_in_t;
  66. // copypaste from demux_real.c - it should match to get it working!
  67. typedef struct dp_hdr_s
  68. {
  69.     uint32_t chunks;    // number of chunks
  70.     uint32_t timestamp;    // timestamp from packet header
  71.     uint32_t len;    // length of actual data
  72.     uint32_t chunktab;    // offset to chunk offset array
  73. } dp_hdr_t;
  74. /* we need exact positions */
  75. struct rv_init_t
  76. {
  77.     short unk1;
  78.     short w;
  79.     short h;
  80.     short unk3;
  81.     int unk2;
  82.     unsigned int * subformat;
  83.     int unk5;
  84.     unsigned int * format;
  85. } rv_init_t;
  86. struct decoder_sys_t
  87. {
  88.     /* library */
  89. #ifdef LOADER
  90.     ldt_fs_t    *ldt_fs;
  91. #endif
  92.     void        *handle;
  93.     void         *rv_handle;
  94.     int          inited;
  95.     char         *plane;
  96. };
  97. int dll_type = 1;
  98. static unsigned long (*rvyuv_custom_message)(cmsg_data_t* ,void*);
  99. static unsigned long (*rvyuv_free)(void*);
  100. static unsigned long (*rvyuv_init)(void*, void*); // initdata,context
  101. static unsigned long (*rvyuv_transform)(char*, char*,transform_in_t*,unsigned int*,void*);
  102. #ifdef WIN32
  103. static unsigned long WINAPI (*wrvyuv_custom_message)(cmsg_data_t* ,void*);
  104. static unsigned long WINAPI (*wrvyuv_free)(void*);
  105. static unsigned long WINAPI (*wrvyuv_init)(void*, void*); // initdata,context
  106. static unsigned long WINAPI (*wrvyuv_transform)(char*, char*,transform_in_t*,unsigned int*,void*);
  107. #endif
  108. /*****************************************************************************
  109.  * Module descriptor
  110.  *****************************************************************************/
  111. static int  Open ( vlc_object_t * );
  112. static void Close( vlc_object_t * );
  113. //static int  OpenPacketizer( vlc_object_t * );
  114. static picture_t *DecodeVideo( decoder_t *, block_t ** );
  115. vlc_module_begin ()
  116.     set_description( N_("RealVideo library decoder") )
  117.     set_capability( "decoder", 10 )
  118.     set_category( CAT_INPUT )
  119.     set_subcategory( SUBCAT_INPUT_VCODEC )
  120.     set_callbacks( Open, Close )
  121. vlc_module_end ()
  122. /*****************************************************************************
  123.  * Local prototypes
  124.  *****************************************************************************/
  125. #ifdef WIN32
  126. static void * load_syms(decoder_t *p_dec, const char *path) 
  127. {
  128.     void *handle;
  129.     msg_Dbg( p_dec, "opening win32 dll '%s'", path);
  130. #ifdef LOADER
  131.     Setup_LDT_Keeper();
  132. #endif
  133.     handle = LoadLibraryA(path);
  134.     msg_Dbg( p_dec, "win32 real codec handle=%p",handle);
  135.     if (!handle)
  136.     {
  137.         msg_Err( p_dec, "Error loading dll");
  138.         return NULL;
  139.     }
  140.     wrvyuv_custom_message = GetProcAddress(handle, "RV20toYUV420CustomMessage");
  141.     wrvyuv_free = GetProcAddress(handle, "RV20toYUV420Free");
  142.     wrvyuv_init = GetProcAddress(handle, "RV20toYUV420Init");
  143.     wrvyuv_transform = GetProcAddress(handle, "RV20toYUV420Transform");
  144.     if (wrvyuv_custom_message && wrvyuv_free && wrvyuv_init && wrvyuv_transform)
  145.     {
  146.         dll_type = 1;
  147.         return handle;
  148.     }
  149.     msg_Err( p_dec, "Error resolving symbols! (version incompatibility?)");
  150.     FreeLibrary(handle);
  151.     return NULL; // error
  152. }
  153. #else
  154. static void * load_syms_linux(decoder_t *p_dec, const char *path) 
  155. {
  156.     void *handle;
  157.     msg_Dbg( p_dec, "opening shared obj '%s'", path);
  158.     handle = dlopen (path, RTLD_LAZY);
  159.     if (!handle) 
  160.     {
  161.         msg_Err( p_dec,"Error: %s",dlerror());
  162.         return NULL;
  163.     }
  164.     rvyuv_custom_message = dlsym(handle, "RV20toYUV420CustomMessage");
  165.     rvyuv_free = dlsym(handle, "RV20toYUV420Free");
  166.     rvyuv_init = dlsym(handle, "RV20toYUV420Init");
  167.     rvyuv_transform = dlsym(handle, "RV20toYUV420Transform");
  168.     if(rvyuv_custom_message && rvyuv_free && rvyuv_init && rvyuv_transform)
  169.     {
  170.         dll_type = 0;
  171.         return handle;
  172.     }
  173.     msg_Err( p_dec,"Error resolving symbols! (version incompatibility?)");
  174.     dlclose(handle);
  175.     return 0;
  176. }
  177. #endif
  178. static vlc_mutex_t rm_mutex = VLC_STATIC_MUTEX;
  179. static int InitVideo(decoder_t *p_dec)
  180. {
  181.     int result;
  182.     struct rv_init_t init_data;
  183.     char fcc[4];
  184.     char *g_decode_path;
  185.     int  i_vide = p_dec->fmt_in.i_extra;
  186.     unsigned int *p_vide = p_dec->fmt_in.p_extra;
  187.     decoder_sys_t *p_sys = malloc( sizeof( decoder_sys_t ) );
  188.     memset(p_sys,0,sizeof( decoder_sys_t ) );
  189.     if( i_vide < 8 )
  190.     {
  191.             msg_Err( p_dec, "missing extra info" );
  192.             free( p_sys );
  193.             return VLC_EGENERIC;
  194.     }
  195.     if (p_sys->plane) free(p_sys->plane);
  196.     p_sys->plane = malloc (p_dec->fmt_in.video.i_width*p_dec->fmt_in.video.i_height*3/2 + 1024 );
  197.     if (NULL == p_sys->plane)
  198.     {
  199.         msg_Err( p_dec, "cannot alloc plane buffer" );
  200.         free( p_sys );
  201.         return VLC_EGENERIC;
  202.     }
  203.     p_dec->p_sys = p_sys;
  204.     p_dec->pf_decode_video = DecodeVideo;
  205.     memcpy( fcc, &p_dec->fmt_in.i_codec, 4 );
  206.     init_data.unk1 = 11;
  207.     init_data.w = p_dec->fmt_in.video.i_width ;
  208.     init_data.h = p_dec->fmt_in.video.i_height ;
  209.     init_data.unk3 = 0;
  210.     init_data.unk2 = 0;
  211.     init_data.subformat = (unsigned int*)p_vide[0];
  212.     init_data.unk5 = 1;
  213.     init_data.format = (unsigned int*)p_vide[1];
  214.     /* first try to load linux dlls, if failed and we're supporting win32 dlls,
  215.        then try to load the windows ones */
  216.     bool b_so_opened = false;
  217. #ifdef WIN32
  218.     g_decode_path="plugins\drv43260.dll";
  219.     if( (p_sys->rv_handle = load_syms(p_dec, g_decode_path)) )
  220.         b_so_opened = true;
  221. #else
  222.     static const char psz_paths[] =
  223.     {
  224.         "/usr/lib/win32"
  225.         "/usr/lib/codecs"
  226.         "/usr/local/RealPlayer8/Codecs"
  227.         "/usr/RealPlayer8/Codecs"
  228.         "/usr/lib/RealPlayer8/Codecs"
  229.         "/opt/RealPlayer8/Codecs"
  230.         "/usr/lib/RealPlayer9/users/Real/Codecs"
  231.         "/usr/lib/RealPlayer10/codecs"
  232.         "/usr/lib/RealPlayer10GOLD/codecs"
  233.         "/usr/lib/helix/player/codecs"
  234.         "/usr/lib64/RealPlayer8/Codecs"
  235.         "/usr/lib64/RealPlayer9/users/Real/Codecs"
  236.         "/usr/lib64/RealPlayer10/codecs"
  237.         "/usr/lib64/RealPlayer10GOLD/codecs"
  238.         "/usr/local/lib/codecs"
  239.         ""
  240.     };
  241.     for( size_t i = 0; psz_paths[i]; i += strlen( psz_paths + i ) + 1 )
  242.     {
  243.         if( asprintf( &g_decode_path, "%s/drv4.so.6.0", psz_paths + i ) != -1 )
  244.         {
  245.             p_sys->rv_handle = load_syms_linux(p_dec, g_decode_path);
  246.             free( g_decode_path );
  247.         }
  248.         if( p_sys->rv_handle )
  249.         {
  250.             b_so_opened = true;
  251.             break;
  252.         }
  253.         if( asprintf( &g_decode_path, "%s/drv3.so.6.0", psz_paths + i ) != -1 )
  254.         {
  255.             p_sys->rv_handle = load_syms_linux(p_dec, g_decode_path);
  256.             free( g_decode_path );
  257.         }
  258.         if( p_sys->rv_handle )
  259.         {
  260.             b_so_opened = true;
  261.             break;
  262.         }
  263.         msg_Dbg( p_dec, "Cannot load real decoder library: %s", g_decode_path);
  264.     }
  265. #endif
  266.     if(!b_so_opened )
  267.     {
  268.         msg_Err( p_dec, "Cannot any real decoder library" );
  269.         free( p_sys );
  270.         return VLC_EGENERIC;
  271.     }
  272.     vlc_mutex_lock( &rm_mutex );
  273.     p_sys->handle=NULL;
  274.     #ifdef WIN32
  275.     if (dll_type == 1)
  276.         result=(*wrvyuv_init)(&init_data, &p_sys->handle);
  277.     else
  278.     #endif
  279.         result=(*rvyuv_init)(&init_data, &p_sys->handle);
  280.     if (result)
  281.     {
  282.         msg_Err( p_dec, "Cannot Init real decoder library: %s",  g_decode_path);
  283.         free( p_sys );
  284.         return VLC_EGENERIC;
  285.     }
  286.     /* setup rv30 codec (codec sub-type and image dimensions): */
  287.     /*if ( p_dec->fmt_in.i_codec == VLC_FOURCC('R','V','3','0') )*/
  288.     if (p_vide[1]>=0x20200002)
  289.     {
  290.         int i, cmsg_cnt;
  291.         uint32_t cmsg24[16]={p_dec->fmt_in.video.i_width,p_dec->fmt_in.video.i_height};
  292.         cmsg_data_t cmsg_data={0x24,1+(p_vide[1]&7), &cmsg24[0]};
  293.         cmsg_cnt = (p_vide[1]&7)*2;
  294.         if (i_vide - 8 < cmsg_cnt) {
  295.                     cmsg_cnt = i_vide - 8;
  296.         }
  297.         for (i = 0; i < cmsg_cnt; i++)
  298.             cmsg24[2+i] = p_vide[8+i]*4;
  299.         #ifdef WIN32
  300.         if (dll_type == 1)
  301.             (*wrvyuv_custom_message)(&cmsg_data,p_sys->handle);
  302.         else
  303.         #endif
  304.             (*rvyuv_custom_message)(&cmsg_data,p_sys->handle);
  305.     }
  306.     /*
  307.     es_format_Init( &p_dec->fmt_out, VIDEO_ES, VLC_FOURCC( 'Y','V','1','2' ));
  308.     es_format_Init( &p_dec->fmt_out, VIDEO_ES, VLC_FOURCC( 'Y','U','Y','2' ));
  309.      */
  310.     es_format_Init( &p_dec->fmt_out, VIDEO_ES, VLC_FOURCC( 'I', '4', '2', '0'));
  311.      
  312.     p_dec->fmt_out.video.i_width = p_dec->fmt_in.video.i_width;
  313.     p_dec->fmt_out.video.i_height= p_dec->fmt_in.video.i_height;
  314.     p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR * p_dec->fmt_in.video.i_width / p_dec->fmt_in.video.i_height;
  315.     p_sys->inited = 0;
  316.     vlc_mutex_unlock( &rm_mutex );
  317.     return VLC_SUCCESS;
  318. }
  319. /*****************************************************************************
  320.  * Open: probe the decoder and return score
  321.  *****************************************************************************
  322.  * Tries to launch a decoder and return score so that the interface is able
  323.  * to choose.
  324.  *****************************************************************************/
  325. static int Open( vlc_object_t *p_this )
  326. {
  327.     decoder_t *p_dec = (decoder_t*)p_this;
  328.     /* create a mutex */
  329.     var_Create( p_this->p_libvlc, "rm_mutex", VLC_VAR_MUTEX );
  330.     switch ( p_dec->fmt_in.i_codec )
  331.     {
  332.     case VLC_FOURCC('R','V','1','0'): 
  333.     case VLC_FOURCC('R','V','2','0'): 
  334.     case VLC_FOURCC('R','V','3','0'):
  335.     case VLC_FOURCC('R','V','4','0'): 
  336.         p_dec->p_sys = NULL;
  337.         p_dec->pf_decode_video = DecodeVideo;
  338.         return InitVideo(p_dec);
  339.     default:
  340.         return VLC_EGENERIC;
  341.     }
  342. }
  343. /*****************************************************************************
  344.  * Close:
  345.  *****************************************************************************/
  346. static void Close( vlc_object_t *p_this )
  347. {
  348.     decoder_t     *p_dec = (decoder_t*)p_this;
  349.     decoder_sys_t *p_sys = p_dec->p_sys;
  350.     /* get lock, avoid segfault */
  351.     vlc_mutex_lock( &rm_mutex );
  352.     #ifdef WIN32
  353.     if (dll_type == 1)
  354.     {
  355.         if (wrvyuv_free)
  356.             wrvyuv_free(p_sys->handle);
  357.     }
  358.     else
  359.     #endif
  360.         if (rvyuv_free)
  361.             rvyuv_free(p_sys->handle);
  362. #ifdef WIN32
  363.     if (dll_type == 1)
  364.     {
  365.         if (p_sys->rv_handle)
  366.             FreeLibrary(p_sys->rv_handle);
  367.     }
  368.     else
  369. #endif
  370.         p_sys->rv_handle=NULL;
  371.     if (p_sys->plane)
  372.     {
  373.         free(p_sys->plane);
  374.         p_sys->plane = NULL;
  375.     }
  376.     msg_Dbg( p_dec, "FreeLibrary ok." );
  377. #ifdef LOADER
  378.     Restore_LDT_Keeper( p_sys->ldt_fs );
  379.     msg_Dbg( p_dec, "Restore_LDT_Keeper" );
  380. #endif
  381.     p_sys->inited = 0;
  382.     vlc_mutex_unlock( &rm_mutex );
  383.     free( p_sys );
  384. }
  385. /*****************************************************************************
  386.  * DecodeVideo:
  387.  *****************************************************************************/
  388. static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
  389. {
  390.     decoder_sys_t *p_sys = p_dec->p_sys;
  391.     block_t       *p_block;
  392.     picture_t     *p_pic;
  393.     mtime_t       i_pts;
  394.     int           result;
  395.     /* We must do open and close in the same thread (unless we do
  396.      * Setup_LDT_Keeper in the main thread before all others */
  397.     if ( pp_block == NULL || *pp_block == NULL )
  398.     {
  399.         return NULL;
  400.     }
  401.     p_block = *pp_block;
  402.     *pp_block = NULL;
  403.     i_pts = p_block->i_pts ? p_block->i_pts : p_block->i_dts;
  404.     vlc_mutex_lock( &rm_mutex );
  405.     p_pic = decoder_NewPicture( p_dec );
  406.     if ( p_pic )
  407.     {
  408.         unsigned int transform_out[5];
  409.         dp_hdr_t dp_hdr;
  410.         transform_in_t transform_in;
  411.         uint32_t pkg_len = ((uint32_t*)p_block->p_buffer)[0];
  412.         unsigned char* dp_data=((unsigned char*)p_block->p_buffer)+8;
  413.         uint32_t* extra=(uint32_t*)(((char*)p_block->p_buffer)+8+pkg_len);
  414.         uint32_t img_size;
  415.         dp_hdr.len = pkg_len;
  416.         dp_hdr.chunktab = 8 + pkg_len;
  417.         dp_hdr.chunks = ((uint32_t*)p_block->p_buffer)[1]-1;
  418.         dp_hdr.timestamp = i_pts;
  419.         memset(&transform_in, 0, sizeof(transform_in_t));
  420.         transform_in.len = dp_hdr.len;
  421.         transform_in.extra = extra;
  422.         transform_in.chunks = dp_hdr.chunks;
  423.         transform_in.timestamp = dp_hdr.timestamp;
  424.         memset (p_sys->plane, 0, p_dec->fmt_in.video.i_width * p_dec->fmt_in.video.i_height *3/2 );
  425.         #ifdef WIN32
  426.         if (dll_type == 1)
  427.             result=(*wrvyuv_transform)(dp_data, p_sys->plane, &transform_in, transform_out, p_sys->handle);
  428.         else
  429.         #endif
  430.             result=(*rvyuv_transform)(dp_data, p_sys->plane, &transform_in, transform_out, p_sys->handle);
  431.         /* msg_Warn(p_dec, "Real Size %d X %d", transform_out[3],
  432.                  transform_out[4]); */
  433.         /* some bug rm file will print the messages :
  434.                 [00000551] realvideo decoder warning: Real Size 320 X 240
  435.                 [00000551] realvideo decoder warning: Real Size 480 X 272
  436.                 [00000551] realvideo decoder warning: Real Size 320 X 240
  437.                 [00000551] realvideo decoder warning: Real Size 320 X 240
  438.                 ...
  439.             so it needs fixing!
  440.         */
  441.         if ( p_sys->inited == 0 )
  442.         {
  443.             /* fix and get the correct image size! */
  444.             if ( p_dec->fmt_in.video.i_width != transform_out[3]
  445.              || p_dec->fmt_in.video.i_height  != transform_out[4] )
  446.             {
  447.                 msg_Warn(p_dec, "Warning, Real's Header give a wrong "
  448.                          "information about media's width and height!"
  449.                          "tRealHeader: t %d X %d  t %d X %d",
  450.                          p_dec->fmt_in.video.i_width,
  451.                          p_dec->fmt_in.video.i_height,
  452.                          transform_out[3],transform_out[4]);
  453.                 
  454.                 if ( p_dec->fmt_in.video.i_width * p_dec->fmt_in.video.i_height >= transform_out[3] * transform_out[4] )
  455.                 {
  456.                     p_dec->fmt_out.video.i_width = 
  457.                     p_dec->fmt_out.video.i_visible_width = 
  458.                     p_dec->fmt_in.video.i_width = transform_out[3] ;
  459.                     p_dec->fmt_out.video.i_height= 
  460.                     p_dec->fmt_out.video.i_visible_height = 
  461.                     p_dec->fmt_in.video.i_height= transform_out[4];
  462.                     p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR * p_dec->fmt_in.video.i_width / p_dec->fmt_in.video.i_height;
  463.                 }
  464.                 else
  465.                 {
  466.                     // TODO: realloc plane's size! but [in fact] it maybe not happen! 
  467.                     msg_Err(p_dec,"plane space not enough ,skip");
  468.                 }
  469.             }
  470.             p_sys->inited = 1;
  471.         }
  472.         img_size = p_dec->fmt_in.video.i_width * p_dec->fmt_in.video.i_height;
  473.         memcpy( p_pic->p[0].p_pixels, p_sys->plane,  img_size);
  474.         memcpy( p_pic->p[1].p_pixels, p_sys->plane + img_size, img_size/4);
  475.         memcpy( p_pic->p[2].p_pixels, p_sys->plane + img_size * 5/4, img_size/4);
  476.         p_pic->date = i_pts ;
  477.         /*  real video frame is small( frame and frame's time-shift is short), 
  478.             so it will become late picture easier (when render-time changed)and
  479.             droped by video-output.*/
  480.         p_pic->b_force = 1;
  481.     }
  482.     vlc_mutex_unlock( &rm_mutex );
  483.     block_Release( p_block );
  484.     return p_pic;
  485. }