2013年11月28日星期四

转换QImage到FFmpeg的internal YUV format

今天正巧有时间,在家里修改并整理一下我3年前写的视频播放和储存代码。FFmpeg更新非常快,突然发现我还在使用2011年09月23日的FFmpeg版本。最新版本已经到了2.1.1(http://ffmpeg.zeranoe.com/builds/win32/dev/),刚刚下载了,试着编译以前写的代码,发现很多API都变了,无法编译了,懒得再进行调整了,放弃使用新版本了,新的特性暂时用不到。我将2011年09月23日的FFmpeg版本作为项目的标准lib,打包上传到服务器上,还有SVN里。

刚刚在修改“转换QImage到FFmpeg的internal YUV format的方法”,这个方法是从QtFFmpegWrapper项目抄来的,https://code.google.com/p/qtffmpegwrapper/。我发现,我刚刚写的新代码中使用的是QImage::Format_RGB888,如果直接使用这个方法转换的frame就会不正确,是黑白的而且尺寸也不对,想了一下,其实只需要将ffmpeg::sws_getCachedContext这个API里的Source PixelFormat 改成PIX_FMT_RGB24就行了,简单而言只要注意将QImage的PixelFormat和AVFrame的PixelFormat正确对应就行了,具体代码如下面所示。

void convertImage_sws(const QImage &img)
{
   // Check if the image matches the size
   if(img.width() != getWidth() || img.height() != getHeight())
   {
      printf("Wrong image size!\n");
      return false;
   }
   if(img.format() != QImage::Format_RGB32 && img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_RGB888)    
   {
      printf("Wrong image format\n");
      return false;
   }

   //img_convert_ctx = ffmpeg::sws_getCachedContext(img_convert_ctx, getWidth(), getHeight(),
      // ffmpeg::PIX_FMT_BGRA, getWidth(),getHeight(), ffmpeg::PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

   img_convert_ctx = ffmpeg::sws_getCachedContext(img_convert_ctx, getWidth(), getHeight(),  ffmpeg::PIX_FMT_RGB24,  getWidth(), getHeight(), ffmpeg::PIX_FMT_YUV420P,  SWS_BICUBIC,  NULL,  NULL,  NULL);

   if (img_convert_ctx == NULL)
   {
      printf("Cannot initialize the conversion context\n");
      return false;
   }

   uint8_t *srcplanes[3];
   srcplanes[0] = (uint8_t*)img.bits();
   srcplanes[1] = 0;
   srcplanes[2] = 0;

   int srcstride[3];
   srcstride[0] = img.bytesPerLine();
   srcstride[1] = 0;
   srcstride[2] = 0;

   ffmpeg::sws_scale(img_convert_ctx, srcplanes, srcstride, 0, getHeight(), ppicture->data, ppicture->linesize);

   return true;
}

2013年11月26日星期二

开始使用C++/CLI编程

一直以来一直是使用C++和C#,最近接触了C++/CLI并开始使用它编写程序,已经写了两三千行程序,使用C++/CLI对一个C++和C#程序员来说简直是轻而易举,C++/CLI也会给我们带来很多好处,有了C++/CLI对于.NET平台上的C++来说就是多了一个非常好用的武器,C++在.NET平台中得到极大的补充,所谓“C++/CLI”是静态C++对象模型到CLI的动态组件对象编程模型的捆绑。简而言之就是如何用C++在·NET中编程,而不是C#或Visual Basic,它实现了ISOC++和.NET的无缝连接。像C#和CLI本身一样符合ISO标准。微软的.NET的基础CLR(Common Language Runtime,通用语言运行时)就是CLI的一个实例。
百度百科,维基百科:
http://baike.baidu.com/view/459502.htm?noadapt=1
http://zh.wikipedia.org/wiki/C%2B%2B/CLI

以下内容转载自《C++/CLI in action》

The Common Language Infrastructure (CLI) is an architecture that supports a dynamic language-independent programming model based on a Virtual Execution System.

The role of C++/CLI

role of c   cli

C++ has been paired with language extensions before, and the result hasn’t always been pretty. Visual C++ 2005 is the first version of a Microsoft C++ compiler that has implemented the C++/CLI specification. This means three things for the C++ developer:
■ C++ can be used to write applications that run on the .NET Framework. There is no need to learn a totally new language or to abandon all the C++ knowledge and experience built up through years of coding.
■ C++/CLI lets developers reuse their native C++ code base, saving the agony of having to rewrite all the existing code to enable it to run on the .NET Framework.
■ C++/CLI is designed to be the lowest-level language for the .NET Framework. For writing purely managed applications, it’s your most powerful choice; or, as I like to say, “C++/CLI actually lets you smell the CLR (Common Language Runtime).”


C++/CLI. C++ with some additional keywords and semantics that support .NET
One of the core aspects of the CLR is a unified type system called the Common Type System (CTS). The CTS defines the model followed by the CLR for the declaration and usage of CLI types.

hierarchy of NET frameworkThe common language specification

What is the .NET Framework?
The .NET Framework provides an abstraction layer on top of the native operating system that allows applications compiled into a special intermediate language called Microsoft Intermediate Language (MSIL) to run under a managed environment— where both execution and memory are managed by various parts of the framework. Its two primary components are the Common Language Runtime (CLR) and an extensive Base Class Library (BCL). The CLR is responsible for the execution of .NET applications, inducing memory management through its built-in Garbage Collector (see the section on memory management for more information), whereas the BCL provides various hierarchical class libraries for creating rich user interfaces (UIs), both for the desktop and for the Web—accessing data, security, web services, and many more commonly-performed programming chores.

2013年11月25日星期一

Ubuntu 12.04无法进GUI mode,无法login解决方法

Ubuntu 12.04 出现 autolaunch error 而且直接booting进入command line,根本无法进GUI mode。如果运行sudo startx会出现类似xauth: error in locking authority file .Xauthority的报错,以下是简单的解决方法:

先删除所有的.Xauthority files

sudo rm -f .Xauthority*

然后sudo startx

如果还有问题

重新安装gnome-desktop-environment

sudo apt-get install aptitude (如果没有装aptitutde)

sudo aptitude install gnome-desktop-environment

 

####

如果进入GUI的login界面,但是无法使用login的password进入系统:

按CTRL+ALT+F1 然后log in 再运行:

sudo chown -R $USER:$USER $HOME

→ 然后重启就可以了

2013年11月22日星期五

TWINCAT 3使用记录3:建立在PC和slave devices之间的连接

如果发现Scan你的EtherCAT Devices出现这样的报错:

no io devices found

就是有可能没有装上TwinCAT EtherCAT的驱动。

在VS2010或2012里TwinCAT -> Show Realtime Compatible Devices可以找到,如下图所示:

show rt ehernet devices

其实就是启动C:\TwinCAT\3.1\System里的TcRteInstall.exe,下图就是这个工具的界面,只需要点击几下鼠标就可以安装好TwinCAT 实时Enternet Adapters。

Installation of RT Ethernet Adapters

也有可能有些Ethernet adapter无法装上驱动,使之可以连接EtherCAT device,我有一台Sony的笔记本就无法装上驱动。如果顺利安装后,就可以Scan到连接的设备,并进行连接,注意:在Config Mode才可以进行实时Scan设备,而Run Mode不可以。

2013年11月21日星期四

TwinCAT 3使用记录2:ADS介绍

今天简要地介绍一下ADS和一个简单的实际例程。ADS就是Automation Device Specification,通过使用Beckhoff的ADS接口可以和一些virtual Automation Device或者是Windows的程序相连。如果安装了TwinCAT3可以在C:\TwinCAT\AdsApi\TcAdsDll\Lib\找到TcAdsDll.lib,这就是我们需要的ADS的lib文件。对于ADS接口,最重要的操作就是READ和WRITE了,以下是API的说明。

long __stdcall AdsSyncWriteReq(    AmsAddr*    pServerAddr,    // Ams address of ADS server
                             unsigned long    indexGroup,        //    index group in ADS server interface
                             unsigned long    indexOffset,    // index offset in ADS server interface
                             unsigned long    length,            // count of bytes to write
                             void*                pData                // pointer to the client buffer
                            );

__declspec( dllexport )
long __stdcall AdsSyncReadReq( AmsAddr*    pAddr,                        // Ams address of ADS server          
                             unsigned long        indexGroup,        //    index group in ADS server interface
                             unsigned long        indexOffset,    // index offset in ADS server interface
                             unsigned long        length,            // count of bytes to read
                             void*                pData                // pointer to the client buffer
                            );

先启动TwinCAT XAE(VS 2010)也就是VS 2010,新建一个TwinCAT的Project。在SYSTEM里的License选项里可以点击“Activate 7 Days Trial License”,然后会出现以下的对话框,填入生成的Code就完成了注册,用于开发,我们可以一直“Activate 7 Days Trial License”并可以使用TwinCAT 3的完整功能。

enter security code

如果我们使用了Beckhoff的EtherCAT的IO模块,并通过Ethernet线和PC相连,我们可以将这个设备和TwinCAT相连,在Solution Explorer里的I/O一栏里,展开它,点击Devices,点鼠标右键,点选Scan就可以连接我们的EtherCAT I/O模块了,如下图所示,也可使用工具栏上的Scan图标。

scan_devices

如果发现有正确连接,就会出现下图的对话框。

IO devices found

点选OK,我们就是Active Free Run了。然后在Solution Explorer会看到Device的信息,如下图所示。

device ethercat

如果我们点选譬如Term 2 (EL2004),并展开它,就会看到这个模块的Channel,如果点击其中一个Channel就会看到上面的I/O,点击这个I/O就会在Variable这个Tab里找到ADS info,如下图所示。

ads infos

接下来我们就要使用这个ADS Info,并使用上面提到的API对其进行读和写。我们可以在以下链接中找到SAMPLE2(写)和SAMPLE3(读),这两个例程使用了SOFT PLC,提供的PLC可以加载到TwinCAT Project里,这里我们不使用PLC而是直接使用我们上面已经连接好的I/O模块:

http://download.beckhoff.com/download/Software/TwinCAT/TwinCAT3/Samples/TC1000-ADS/ADS/C/

#include <iostream>
#include <windows.h>
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsDef.h"
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsAPI.h"

using namespace std;
void main()
{
  long     nErr, nPort;
  AmsAddr  Addr;
  PAmsAddr pAddr = &Addr;
  DWORD    dwData;

  // Open communication port on the ADS router
  nPort = AdsPortOpen();
  nErr = AdsGetLocalAddress(pAddr);
  if (nErr) cerr << "Error: AdsGetLocalAddress: " << nErr << '\n';
  pAddr->port = 11;

  // Read the vlaue of the user, who has to be written to the PLC
  cout << "Value: ";
  cin >> dwData;

  //Port: 11, IGrp: 0x3040010, IOffs: 0xC10000D1, Len: 1
  nErr = AdsSyncWriteReq( pAddr, 0x3040010, 0xC10000D1, 0x1, &dwData );
  if (nErr) cerr << "Error: AdsSyncWriteReq: " << nErr << '\n';

  // Close the communication port
  nErr = AdsPortClose();
  if (nErr) cerr << "Error: AdsPortClose: " << nErr << '\n';
}

例程中的代码只需进行两处的改动(红笔处),就可以将我们输入的Data通过ADS接口传递给我们的EtherCAT I/O模块,这里使用的port of ADS server,index group in ADS server interface,index offset in ADS server interface,count of bytes to write,就是我们在上图看到的我们读到的ADS info。对于Read的例程SAMPLE3我就不多加描述了,就是使用AdsSyncReadReq这个API,然后给其相对应的ADS info就行。

项目经验:扬长避短,使用外包

最近真正开始完全接手并开始管理两个项目,多带了两个员工,积累了一些经验,最近的心得是:一定要注意扬长避短,遇到自己的短处时候可以使用外包。

譬如,我带的项目组的优势是复杂工程能力,软硬件整合能力,而复杂图形算法的设计能力是我们的弱点,以前我总是想要自己解决所有的事情,在复杂图形算法的设计上浪费了很多时间,花了大量的精力进行研究学习,测试,正因为我们不擅长,事倍功半。现在我将这块外包,集中精力维护我们的优点,提高优势,努力保持我们的不可替代性,这个月来我们得到了很多的收获和提高。其实,劳动和报酬不是成正比,而是和劳动的不可替代性成正比。

2013年11月18日星期一

TwinCAT 3使用记录1

我发现TwinCAT 3在一些PC上不能正常使用,研究了半天才发现TwinCAT 3需要Intel’s Virtualization Technology Extentions (VTx)或者AMD (AMD-V)。需要在BIOS启动这个功能。有些电脑的BIOS比较老还必须要flash它才能得到这个功能,当然了这个CPU必须支持Virtualization Technology。

关于x86 Virtualization 详见:http://en.wikipedia.org/wiki/Virtualization_Technology

关于Intel CPU的Virtualization列表详见:http://ark.intel.com/Products/VirtualizationTechnology

2013年11月1日星期五

ASP.NET MVC 4使用技巧9:使用Google Charts和JSON

Google Charts 令人爱不释手,功能强大而且简单美观,文档非常完善。

https://developers.google.com/chart/

这里同时推荐一下Playerground,真是是一个非常好用的“工具”,可以非常方便地进行测试。

http://code.google.com/apis/ajax/playground/

如果想画一个line chart,并使用JSON得到做图的数据,很简单,以下就是一个简单的例子,在我们的.cshtml中添加上我们需要的js代码,在这个例子中,

  • 引用jsapi库并使用一系列Google Chart API,进行做图。
  • 通过点击一个button激活做图function。
  • 通过google.visualization.events.addListener得到点击line的事件。
  • 通过$.post('/YourController/GetDrawJsonData', {}, function (d) { … …); }); 从我们的Controller中得到Json数据。
<script type="text/javascript" src="//www.google.com/jsapi"></script>



    <script type="text/javascript">






        google.load("visualization", "1", { packages: ["corechart"] });



        google.setOnLoadCallback(drawChart);



        function drawChart() {



            var chart = new google.visualization.LineChart(document.getElementById('chart_div'));






            var button_show_all = document.getElementById('show_all');



            //-- Set a button onclick event



            // Multi graph.



            button_show_all.onclick = function () {



                var options =



                {



                    title: 'All Heuristic Methods',



                    colors: ['#E6E6E6'],



                    //colors: ['#93ACE7'],



                    legend: { position: 'none' }



                    //legend: { position: 'top', maxLines: '5' }



                    //series: [{ color: 'blue', visibleInLegend: true }, { color: 'blue', visibleInLegend: true }]



                };






                // Add our selection handler.



                google.visualization.events.addListener(chart, 'select', lineChartHandler);



                //-- Chart click event



                function lineChartHandler() {



                    var selection = chart.getSelection();



                    if (selection.length > 0) {



                        alert('A Line was selected');



                    }



                }






                $.post('/Plan/GetDrawJsonData', {},



                function (d) {



                    //alert(d);



                    var data = google.visualization.arrayToDataTable(d);



                    // At the end draw the chart.



                    chart.draw(data, options);



                });



            }



   }






</script>








它的html代码就更简单了:



<input id="show_all" type="button" class="btn btn-info" value="Show All Charts"  />



<br />



<div id="chart_div" style="width: auto; height: 400px;">



</div>





在Controller中只需要加入生成JSON数据的方法:



public ActionResult GetDrawJsonData()



{



     List<object> data_todraw = ... ... ...;



    return Json(data_todraw);



}


 


进阶一下,如果想要通过JSON改变做图的options,譬如说是颜色,其实也很方便,先在js中加入一个chart_opt的arrary:



var chart_opt = new Object();



chart_opt.title = "Heuristic Method";



var colors = new Array();



colors[0] = "#93ACE7"



chart_opt.colors = colors;



var lengend = new Object();



lengend.position = 'none';



chart_opt.legend = lengend;


 


然后通过一个function得到json数据,这里的row: input_counter是一个输入,我们的Controller的方法可以通过这样的方式得到这个输入:



$.post('/YourController/GetDrawJsonOptionSingle', { row: input_counter },



function (f) {



   //console.log(f);



   //If for some reason you cannot modify your server side script to provide 



   //a valid JSON in the tags property you could still use eval instead of $.parseJSON:var tags = $.parseJSON(response.tags);



   var colors_tmp = eval(f);



   console.log(colors_tmp);



   for (i = 0; i < colors_tmp.colors.length; i++) {



       colors[i] = colors_tmp.colors[i];



   }



});


与之对应的Controller里的method,需要使用一个Class里面定义colors的List,最后通过return Json(…)返回JSON数据:



public class ChartOptions
{
    public List<string> colors;
}


 

public ActionResult GetDrawJsonOptionSingle(int row)
{

 

    ChartOptions tmp = new ChartOptions();



    tmp.colors = new List<string>();



    for (int i = 0; i < ROW_COUNT_ALL; i++)



    {



        if (i == row)



        {



            tmp.colors.Add("#F30A0A");



        }



        else



        {



            tmp.colors.Add("#E6E6E6");



        }



    }



    return Json(tmp);



}