2012-06-29 102 views

回答

17

這樣做的唯一可行的方法是手動提取幀,緩衝它們(在內存或文件上),然後以相反的順序重新加載它們。

問題是視頻壓縮器都在利用時間冗餘 - 兩個連續幀大部分時間非常相似的事實。所以,他們不時編碼一個全幀(通常每幾百幀),然後只發送前一個和當前的差異。

現在,爲了解碼工作,它必須以相同的順序完成 - 解碼一個關鍵幀(一個完整的),然後爲每個新幀添加差異來獲取當前圖像。

該策略使得在視頻中反轉播放變得非常困難。有幾種技術,但都涉及緩衝。

現在,您可能已經看到了由Astor描述的CV_CAP_PROP_POS_FRAMES參數。看起來沒問題,但由於上述問題,OpenCV無法正確跳轉到特定幀(在這些問題上存在多個錯誤)。他們(OpenCV開發者)正在研究一些解決方案,但即使這些解決方案也會非常緩慢(它們涉及回到上一個關鍵幀,然後解碼回選定的一個)。如果使用這種技術,每幀平均必須被解碼數百次,使其非常緩慢。然而,它不起作用。

編輯 如果您追求緩衝方式來逆轉它,請記住,解碼後的視頻會快速消耗常規計算機的內存資源。一個普通的720p視頻一分鐘長需要4.7GB解壓縮的內存!將幀作爲單個文件存儲在磁盤上是解決此問題的實際解決方案。

+0

好的答案+1。不知道。你是否爲OpenCV編碼? – ArtemStorozhuk

+0

:)不是yey,雖然我正在考慮一些補丁。但是我在VideoCapture syncronization方面遇到了一些問題,並且發現了一些缺陷。 – Sam

+0

好吧,謝謝你的幫助 – darasan

1

是的,這是可能的。請參閱評論代碼:

//create videocapture 
VideoCapture cap("video.avi"); 

//seek to the end of file 
cap.set(CV_CAP_PROP_POS_AVI_RATIO, 1); 

//count frames 
int number_of_frames = cap.get(CV_CAP_PROP_POS_FRAMES); 

//create Mat frame and window to display 
Mat frame; 
namedWindow("window"); 

//main loop 
while (number_of_frames > 0) 
{ 
    //decrease frames and move to needed frame in file 
    number_of_frames--; 
    cap.set(CV_CAP_PROP_POS_FRAMES, number_of_frames); 

    //grab frame and display it 
    cap >> frame; 
    imshow("window", frame); 

    //wait for displaying 
    if (waitKey(30) >= 0) 
    { 
     break; 
    } 
} 

也讀this文章。

+0

cap.set(CV_CAP_PROP_POS_FRAMES,number_of_frames);確實會影響CPU,但工作。 –

2

另一種解決方案,類似於ArtemStorozhuk's answer是使用FPS從幀域移動到時域,然後尋求向後使用CV_CAP_PROP_POS_MSEC(其不錘擊CPU等CV_CAP_PROP_POS_FRAMES可以)。這裏是我的示例代碼,它完全適用於.mpg,只使用大約50%的CPU。

#include <opencv2/opencv.hpp> 

int main (int argc, char* argv[]) 
{ 
    cv::VideoCapture cap(argv[1]); 

    double frame_rate = cap.get(CV_CAP_PROP_FPS); 

    // Calculate number of msec per frame. 
    // (msec/sec/frames/sec = msec/frame) 
    double frame_msec = 1000/frame_rate; 

    // Seek to the end of the video. 
    cap.set(CV_CAP_PROP_POS_AVI_RATIO, 1); 

    // Get video length (because we're at the end). 
    double video_time = cap.get(CV_CAP_PROP_POS_MSEC); 

    cv::Mat frame; 
    cv::namedWindow("window"); 

    while (video_time > 0) 
    { 
    // Decrease video time by number of msec in one frame 
    // and seek to the new time. 
    video_time -= frame_msec; 
    cap.set(CV_CAP_PROP_POS_MSEC, video_time); 

    // Grab the frame and display it. 
    cap >> frame; 
    cv::imshow("window", frame); 

    // Necessary for opencv's event loop to work. 
    // Wait for the length of one frame before 
    // continuing the loop. Exit if the user presses 
    // any key. If you want the video to play faster 
    // or slower, adjust the parameter accordingly.  
    if (cv::waitKey(frame_msec) >= 0) 
     break; 
    } 
} 
+0

所以..尋求msec是不是CPU消耗,逐幀尋找?爲什麼?因爲壓縮? – nkint

+0

我認爲這與視頻編碼的方式有關......每個數據包中都有一個時間戳,指示自視頻開始以來的時間,所以在視頻中尋找特定時間是一種簡單的二進制搜索操作。但我並不是視頻編碼方面的專家,所以請在評論中加上一點鹽分。 –