2013-04-03 41 views
8

Tôi muốn tạo hình thu nhỏ cho video AVC MPEG-4 bằng Gstreamer và Python. Về cơ bản:Cách tạo hình thu nhỏ video bằng Python và Gstreamer

  1. Open file video
  2. Seek đến một điểm nhất định trong thời gian (ví dụ 5 giây)
  3. Grab khung tại thời điểm đó
  4. Save the khung để đĩa như một tập tin .jpg

Tôi đã xem this other similar question, nhưng tôi không thể tìm ra cách tự động tìm kiếm và chụp khung mà không cần người dùng nhập.

Tóm lại, làm thế nào tôi có thể chụp hình thu nhỏ video bằng Gstreamer và Python theo các bước ở trên?

+1

Lưu ý rằng "5 giây" có thể không hoạt động. Đối với nhiều phim thương mại, bạn sẽ chỉ nhận được phần giới thiệu/logo. Cố gắng tìm các khung màu đen (chúng cho biết các thay đổi cảnh) và sau đó tìm kiếm một vài giây vào cảnh. Cung cấp cho người dùng 4-5 người để tìm hình ảnh dễ nhận ra. –

+0

Điều này dành cho các video cá nhân dài hơn 5 giây. Trong mọi trường hợp, con số 5 giây chỉ là tùy ý và vì lợi ích của ví dụ. Có thể là 2, 10 hoặc bất kỳ giá trị nào khác bên dưới, giả sử là 30 giây. –

Trả lời

7

Để xây dựng trên câu trả lời ensonic 's, đây là một ví dụ:

import os 
import sys 

import gst 

def get_frame(path, offset=5, caps=gst.Caps('image/png')): 
    pipeline = gst.parse_launch('playbin2') 
    pipeline.props.uri = 'file://' + os.path.abspath(path) 
    pipeline.props.audio_sink = gst.element_factory_make('fakesink') 
    pipeline.props.video_sink = gst.element_factory_make('fakesink') 
    pipeline.set_state(gst.STATE_PAUSED) 
    # Wait for state change to finish. 
    pipeline.get_state() 
    assert pipeline.seek_simple(
     gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, offset * gst.SECOND) 
    # Wait for seek to finish. 
    pipeline.get_state() 
    buffer = pipeline.emit('convert-frame', caps) 
    pipeline.set_state(gst.STATE_NULL) 
    return buffer 

def main(): 
    buf = get_frame(sys.argv[1]) 

    with file('frame.png', 'w') as fh: 
     fh.write(str(buf)) 

if __name__ == '__main__': 
    main() 

này tạo ra một hình ảnh PNG. Bạn có thể lấy dữ liệu hình ảnh thô bằng cách sử dụng gst.Caps("video/x-raw-rgb,bpp=24,depth=24") hoặc một cái gì đó tương tự.

Lưu ý rằng trong GStreamer 1.0 (trái ngược với 0,10), playbin2 đã được đổi tên thành playbin và tín hiệu convert-frame được đặt tên convert-sample.

Cơ chế tìm kiếm được giải thích trong this chapter of the GStreamer Application Development Manual. Tài liệu 0.10 playbin2 dường như không còn trực tuyến, nhưng tài liệu cho 1.0 là here.

+0

Đó là * tuyệt vời *, cảm ơn! Tôi đã cố gắng chuyển mã sang PyGI, và tôi đã tìm thấy một vấn đề trong đó 'gst.Caps ('image/png')' không còn hoạt động nữa, vì Gst.Caps mới() không có bất kỳ đối số nào, và Tôi đã không tìm thấy bất kỳ thay thế ('Gst.caps_from_string ('image/png')' segfaults). Bất kỳ con trỏ? –

+0

Tôi đã tạo [một gist với phiên bản PyGI] (https://gist.github.com/dplanella/5563018) và nó chạy mà không có lỗi. Tuy nhiên, nó tạo ra các tệp .png không đọc được. Nếu bất kỳ chuyên gia GStreamer nào có thể nhận ra sai lầm, bất kỳ con trỏ nào cũng sẽ được chào đón, cảm ơn! –

+0

Tôi đoán là 'str (buf)' không còn làm những gì nó sử dụng và bây giờ nó cho bạn một cái gì đó như '" "'. Bạn đã thử xem tệp PNG kết quả chưa? Tôi đoán bạn muốn một cái gì đó như 'buf.data'. – daf

2

Sử dụng playbin2. đặt uri thành tệp phương tiện, sử dụng gst_element_seek_simple để tìm kiếm vị trí thời gian mong muốn và sau đó sử dụng g_signal_emit để gọi tín hiệu hành động "chuyển đổi khung".

+0

Cảm ơn câu trả lời của bạn. Bạn có quan tâm đến việc xây dựng một chút với đoạn mã có lẽ không? Tôi hiểu một phần với 'playbin2', nhưng không phải' gst_element_seek_simple() 'hay' gst.element_seek_simple() 'dường như có sẵn trong Python. –

+0

Ok, đã tìm ra rằng có 'gst.Element.seek_simple()' trong Python, và cách sử dụng nó. Tuy nhiên, một đoạn mã Python sẽ thực sự hữu ích, vì bây giờ điều tiếp theo để tìm ra là làm thế nào để sử dụng 'g_signal_emit' tương đương. –

+0

Xin lỗi, tôi không thể giúp n phía python:/ – ensonic

2

Một ví dụ trong Vala, với GStreamer 1.0:

var playbin = Gst.ElementFactory.make ("playbin", null); 
playbin.set ("uri", "file:///path/to/file"); 
// some code here. 
var caps = Gst.Caps.from_string("image/png"); 
Gst.Sample sample; 
Signal.emit_by_name(playbin, "convert-sample", caps, out sample); 
if(sample == null) 
    return; 
var sample_caps = sample.get_caps(); 
if(sample_caps == null) 
    return; 
unowned Gst.Structure structure = sample_caps.get_structure(0); 
int width = (int)structure.get_value ("width"); 
int height = (int)structure.get_value ("height"); 
var memory = sample.get_buffer().get_memory (0); 
Gst.MapInfo info; 
memory.map (out info, Gst.MapFlags.READ); 
uint8[] data = info.data; 
+0

Cảm ơn! Tuy nhiên, tôi vẫn đang tìm kiếm một ví dụ Python. Dường như là do [lỗi này] (https://bugzilla.gnome.org/show_bug.cgi?id=678663) điều này vẫn không thể thực hiện được với GStreamer 1.0 và Python: / –

1

Đó là một câu hỏi cũ nhưng tôi vẫn chưa tìm thấy nó ghi lại bất cứ nơi nào.
tôi thấy rằng sau đây làm việc trên một đoạn video chơi với GStreamer 1,0

import gi 
import time 
gi.require_version('Gst', '1.0') 
from gi.repository import Gst 

def get_frame(): 
    caps = Gst.Caps('image/png') 
    pipeline = Gst.ElementFactory.make("playbin", "playbin") 
    pipeline.set_property('uri','file:///home/rolf/GWPE.mp4') 
    pipeline.set_state(Gst.State.PLAYING) 
    #Allow time for it to start 
    time.sleep(0.5) 
    # jump 30 seconds 
    seek_time = 30 * Gst.SECOND 
    pipeline.seek(1.0, Gst.Format.TIME,(Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE),Gst.SeekType.SET, seek_time , Gst.SeekType.NONE, -1) 

    #Allow video to run to prove it's working, then take snapshot 
    time.sleep(1) 
    buffer = pipeline.emit('convert-sample', caps) 
    buff = buffer.get_buffer() 
    result, map = buff.map(Gst.MapFlags.READ) 
    if result: 
     data = map.data 
     pipeline.set_state(Gst.State.NULL) 
     return data 
    else: 
     return 

if __name__ == '__main__': 
    Gst.init(None) 
    image = get_frame() 
    with open('frame.png', 'wb') as snapshot: 
     snapshot.write(image) 

Mã nên chạy với cả python2 và Python3, tôi hy vọng nó sẽ giúp một ai đó.

Các vấn đề liên quan