1 /** 2 * Get frames from a video file by invoking ffmpeg. 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.utils.graphics.ffmpeg; 15 16 import std.exception; 17 import std.typecons; 18 19 import ae.utils.graphics.color; 20 import ae.utils.graphics.image; 21 22 private struct VideoStreamImpl 23 { 24 @property ref Image!BGR front() 25 { 26 return frame; 27 } 28 29 @property bool empty() { return done; } 30 31 void popFront() 32 { 33 auto stream = pipes.stdout; 34 auto headerBuf = frameBuf[0..Header.sizeof]; 35 if (!stream.readExactly(headerBuf)) 36 { 37 done = true; 38 return; 39 } 40 41 auto pHeader = cast(Header*)headerBuf.ptr; 42 frameBuf.length = pHeader.bfSize; 43 auto dataBuf = frameBuf[Header.sizeof..$]; 44 enforce(stream.readExactly(dataBuf), "Unexpected end of stream"); 45 46 frameBuf.parseBMP!BGR(frame); 47 } 48 49 @disable this(this); 50 51 ~this() 52 { 53 if (done) 54 wait(pipes.pid); 55 else 56 kill(pipes.pid); 57 } 58 59 private void initialize(string fn) 60 { 61 pipes = pipeProcess([ 62 "ffmpeg", 63 // Be quiet 64 "-loglevel", "panic", 65 // Specify input 66 "-i", fn, 67 // No audio 68 "-an", 69 // Specify output codec 70 "-vcodec", "bmp", 71 // Specify output format 72 "-f", "image2pipe", 73 // Specify output 74 "-" 75 ], Redirect.stdout); 76 77 frameBuf.length = Header.sizeof; 78 79 popFront(); 80 } 81 82 private: 83 import std.process; 84 85 ProcessPipes pipes; 86 bool done; 87 88 alias BitmapHeader!3 Header; 89 ubyte[] frameBuf; 90 Image!BGR frame; 91 } 92 93 struct VideoStream 94 { 95 RefCounted!VideoStreamImpl impl; 96 this(string fn) { impl.initialize(fn); } 97 @property ref Image!BGR front() { return impl.front; } 98 @property bool empty() { return impl.empty; } 99 void popFront() { impl.popFront(); } 100 } 101 //alias RefCounted!VideoStreamImpl VideoStream; 102 103 VideoStream streamVideo(string fn) { return VideoStream(fn); } 104 105 private: 106 107 import std.stdio; 108 109 bool readExactly(ref File f, ubyte[] buf) 110 { 111 auto read = f.rawRead(buf); 112 if (read.length==0) return false; 113 enforce(read.length == buf.length, "Unexpected end of stream"); 114 return true; 115 }