天天看點

借助開源項目,又好又快的實作視訊檔案”劇情連拍(劇情截圖)”功能

用過QQ影音(或其他類似播放器)的可能都知道,QQ影音有一個功能叫“劇情連拍”,可以對一部影片在不同時段進行截圖,然後把這些截圖放在一張并生成單獨的圖檔。通過劇情圖,可以一目了然的看到整部影片的畫面風格,也就能大緻猜出這部影片的類型,再加上字幕,甚至可以大概猜出影片的故事梗概。本人前些日子針對這個功能做了一些研究,小有成果,先上兩張效果圖:

1. 

借助開源項目,又好又快的實作視訊檔案”劇情連拍(劇情截圖)”功能
2. 
借助開源項目,又好又快的實作視訊檔案”劇情連拍(劇情截圖)”功能
  怎麼樣,效果還可以吧?要實作這種程式需要完成以下幾種功能

  1. 實作從視訊中截圖的功能
  2. 分析檔案格式,讀取視訊寬高和時長
  3. 把所有截圖繪制在一張圖像中

  下面一一道來:

1. 實作從視訊中截圖的功能

  首先第一個,也是最關鍵的一點,實作視訊截圖。對于截圖這種需要解碼視訊的功能,我們最好借助于現有程式,著名的開源項目ffmpeg便可完成此功能,還有鼎鼎大名的開源播放器MPlayer,也提供的截圖的指令接口,隻需要簡單的調用即可,兩個程式生成的截圖品質差不多,效率上卻有些不同。

ffmpeg的調用指令為:

ffmpeg -i input.rmvb -y -f image2 -ss 08.010 -t 0.001 -s 352x240 output.jpg

  其中,-ss指定了截圖的起始時間

  當然,這隻能截取一張圖檔,我們要的是劇情連拍啊!不用着急,雖然沒有現成的,我們可以自己來做,隻要讀取到影片的時長,我們就能夠計算出需要在哪些時間來截圖,這樣,通過均勻分布截圖時間,多次調用截圖程式,就能生成一連串的截圖,也就是劇情了。那怎麼才能讀取影片時長呢,來看第二步。

2. 分析檔案格式,讀取視訊寬高和時長

  讀取視訊寬高和時長,需要解析視訊格式。如今,媒體容器格式繁多複雜,要想準确的判斷一個視訊檔案的格式和編碼,不是件容易的事情。還好,我們有偉大的開源項目,用很多開源軟體都可以讀取出視訊格式,這裡推薦MediaInfo,因為它似乎就是為這個目的而建立的,生成的屬性資訊詳細而準确,正是我們想要的。此外,MediaInfo還提供了一個動态連結庫"MediaInfo.dll"。

借助開源項目,又好又快的實作視訊檔案”劇情連拍(劇情截圖)”功能

  很明顯,MediaInfo告訴了你,這個影片的時長(Duration),寬度(Width)和高度(Height),當然還有其他你想要或不想要的資訊,夠了。

3. 把所有截圖繪制在一張圖像中

  這個沒什麼好說的,隻要前兩步做出來了,這一步基本不是什麼問題,根據視訊的寬和高,以及最終結果圖檔的寬和高,計算出你需要對截圖進行縮放的比例,然後把圖像繪制在一起,生成新的圖像即可。下面是用 Qt 實作這一步的代碼:

借助開源項目,又好又快的實作視訊檔案”劇情連拍(劇情截圖)”功能

1 int headerheight = 70; // 頂上留一部分高度用了繪制logo和檔案資訊

2   int interval = 4;

3 int column_count = basecolumn_;

4 int total_width = column_count * one_img_width + (column_count+1) * interval;

5 int row_count = (imglist.size() + column_count-1 ) / column_count;

6 int total_height = row_count * one_img_height + (row_count+1) * interval + headerheight;

7

8 int row_no = 0;

9 int col_no = 0;

10 QImage totalImage(total_width, total_height, QImage::Format_ARGB32_Premultiplied);

11 totalImage.fill(qRgb(255, 255, 255));

12 QPainter imagePainter(&totalImage);

13 imagePainter.setRenderHint(QPainter::Antialiasing, true);

14 imagePainter.setPen(QPen(Qt::black, 1, Qt::SolidLine/*, Qt::RoundCap, Qt::RoundJoin*/));

15 imagePainter.setFont(QFont(tr("楷體"), 13, QFont::Bold));

16 QString titlename(tr("影片名:"));

17 titlename.append(QString::fromStdString(cinfo.title.c_str()));

18 titlename.append(tr("\t格式:"));

19 titlename.append(QString::fromStdString(cinfo.format_name));

20 imagePainter.drawText(150, 30, titlename);

21 std::ostringstream oss;

22 oss << "檔案大小:" << cinfo.size / 1000000 << "MB\t視訊尺寸:"

23 << cinfo.width << "x" << cinfo.height << "\t視訊時長:";

24 QString info = QString::fromStdString(oss.str());

25 info.append(TimetoStr(cinfo.duration));

26 imagePainter.drawText(150, 55, info);

27

28

29 for (list<QImage>::const_iterator it = imglist.begin();

30 it != imglist.end(); ++it)

31 {

32 int img_x = col_no * one_img_width + (col_no+1) * interval;

33 int img_y = row_no * one_img_height + (row_no+1) * interval + headerheight;

34

35 imagePainter.drawImage(img_x, img_y, *it);

36

37 col_no++;

38 if ( (col_no % column_count) == 0 )

39 {

40 row_no ++;

41 col_no = 0;

42 }

43 }

44

45 imagePainter.end();

46 totalImage.save(QString::fromStdString(outname));

借助開源項目,又好又快的實作視訊檔案”劇情連拍(劇情截圖)”功能

  這樣,模仿QQ影音劇情連拍的功能就實作了,然後呢,就可以在此基礎上做其他的應用了。我是用Qt開發的,當然,很簡單就能轉換成其他的語言和類庫來實作。

繼續閱讀