mirror of
https://git.femboyfinancial.jp/james/lipsync.git
synced 2024-11-24 19:51:59 -08:00
252 lines
9.8 KiB
C#
252 lines
9.8 KiB
C#
|
/*
|
|||
|
* PipedAviWriter.cs
|
|||
|
* Copyright (c) 2008-2009 kbinani
|
|||
|
*
|
|||
|
* This file is part of Boare.Lib.Media.
|
|||
|
*
|
|||
|
* Boare.Lib.Media is free software; you can redistribute it and/or
|
|||
|
* modify it under the terms of the BSD License.
|
|||
|
*
|
|||
|
* Boare.Lib.Media is distributed in the hope that it will be useful,
|
|||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|||
|
*/
|
|||
|
#if !MONO
|
|||
|
#define TEST
|
|||
|
using System;
|
|||
|
using System.Diagnostics;
|
|||
|
using System.Drawing;
|
|||
|
using System.Drawing.Imaging;
|
|||
|
using System.IO;
|
|||
|
//using System.IO.Pipes;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
using System.Threading;
|
|||
|
|
|||
|
using bocoree;
|
|||
|
|
|||
|
namespace Boare.Lib.Media {
|
|||
|
|
|||
|
public class PipedAviWriter {
|
|||
|
private const string _PIPE_NAME = "fifo";
|
|||
|
private uint m_scale = 1;
|
|||
|
private uint m_rate = 30;
|
|||
|
#if TEST
|
|||
|
private FileStream m_stream = null;
|
|||
|
#else
|
|||
|
private NamedPipeServerStream m_stream = null;
|
|||
|
#endif
|
|||
|
private MainAVIHeader m_main_avi_header;
|
|||
|
private uint m_bitmapsize;
|
|||
|
private bool m_header_written = false;
|
|||
|
private ulong m_frames;
|
|||
|
private Thread m_ffmpeg = null;
|
|||
|
private PixelFormat m_pix_fmt = PixelFormat.Format24bppRgb;
|
|||
|
private int m_bit_count = 24;
|
|||
|
|
|||
|
public bool AddFrame( Bitmap bmp ) {
|
|||
|
if ( bmp.PixelFormat != m_pix_fmt ) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
BitmapData bdat = bmp.LockBits( new Rectangle( 0, 0, bmp.Width, bmp.Height ),
|
|||
|
ImageLockMode.ReadOnly,
|
|||
|
bmp.PixelFormat );
|
|||
|
BinaryWriter bw = new BinaryWriter( new MemoryStream() );
|
|||
|
if ( !m_header_written ) {
|
|||
|
m_bitmapsize = (uint)(bdat.Stride * bdat.Height);
|
|||
|
//m_stream.SetLength( (long)(0xdc + (m_bitmapsize + 0x8) * m_frames) );
|
|||
|
|
|||
|
/*m_main_avi_header.dwWidth = (uint)bdat.Width;
|
|||
|
m_main_avi_header.dwHeight = (uint)bdat.Height;// bmp%infoHeader%Height
|
|||
|
m_main_avi_header.dwMaxBytesPerSec = (uint)((float)bdat.Stride * (float)bdat.Height * (float)m_rate / (float)m_scale);
|
|||
|
m_main_avi_header.dwStreams = 1;
|
|||
|
m_main_avi_header.dwSuggestedBufferSize = (uint)(bdat.Stride * bdat.Height);
|
|||
|
|
|||
|
AVIStreamHeader stream_header = new AVIStreamHeader();
|
|||
|
stream_header.fccType = Util.mmioFOURCC( "vids" );
|
|||
|
stream_header.fccHandler = 0;
|
|||
|
stream_header.dwFlags = 0;
|
|||
|
stream_header.dwReserved1 = 0;
|
|||
|
stream_header.dwInitialFrames = 0;
|
|||
|
stream_header.dwScale = m_scale;
|
|||
|
stream_header.dwRate = m_rate;
|
|||
|
stream_header.dwStart = 0;
|
|||
|
stream_header.dwSuggestedBufferSize = m_main_avi_header.dwSuggestedBufferSize;
|
|||
|
stream_header.dwQuality = 0;
|
|||
|
stream_header.dwSampleSize = 0;
|
|||
|
|
|||
|
BITMAPINFOHEADER bih = new BITMAPINFOHEADER(); //(BITMAPINFOHEADER)Marshal.PtrToStructure( Marshal.AllocHGlobal( sizeof( BITMAPINFOHEADER ) ), typeof( BITMAPINFOHEADER ) );
|
|||
|
bih.biSize = (uint)(Marshal.SizeOf( bih ));
|
|||
|
bih.biWidth = bdat.Width;
|
|||
|
bih.biHeight = bdat.Height;
|
|||
|
bih.biPlanes = 1;
|
|||
|
bih.biBitCount = m_pix_fmt == PixelFormat.Format24bppRgb ? (short)24 : (short)32;
|
|||
|
bih.biCompression = 0;//BI_RGB
|
|||
|
bih.biSizeImage = (uint)(bdat.Stride * bdat.Height);
|
|||
|
bih.biXPelsPerMeter = 0;
|
|||
|
bih.biYPelsPerMeter = 0;
|
|||
|
bih.biClrUsed = 0;
|
|||
|
bih.biClrImportant = 0;
|
|||
|
|
|||
|
bw.Write( "RIFF".ToCharArray() );
|
|||
|
bw.Write( (uint)(0xdc + (m_bitmapsize + 0x8) * m_frames) );
|
|||
|
bw.Write( "AVI ".ToCharArray() );
|
|||
|
bw.Write( "LIST".ToCharArray() );
|
|||
|
bw.Write( (uint)0xc0 );
|
|||
|
bw.Write( "hdrl".ToCharArray() );
|
|||
|
bw.Write( "avih".ToCharArray() );
|
|||
|
bw.Write( (uint)0x38 );
|
|||
|
m_main_avi_header.Write( bw.BaseStream );
|
|||
|
bw.Write( "LIST".ToCharArray() );
|
|||
|
bw.Write( (uint)0x7C );
|
|||
|
bw.Write( "strl".ToCharArray() );
|
|||
|
bw.Write( "strh".ToCharArray() );
|
|||
|
bw.Write( (uint)0x38 );
|
|||
|
stream_header.Write( bw.BaseStream );
|
|||
|
bw.Write( (uint)0x0 );
|
|||
|
bw.Write( (uint)0x0 );
|
|||
|
bw.Write( "strf".ToCharArray() );
|
|||
|
bw.Write( (uint)0x28 );
|
|||
|
bih.Write( bw.BaseStream );
|
|||
|
bw.Write( "LIST".ToCharArray() );
|
|||
|
bw.Write( (uint)((m_bitmapsize + 0x8) * m_frames) );
|
|||
|
bw.Write( "movi".ToCharArray() );*/
|
|||
|
|
|||
|
m_header_written = true;
|
|||
|
}
|
|||
|
|
|||
|
//bw.Write( "00db" );
|
|||
|
//bw.Write( (uint)m_bitmapsize );
|
|||
|
int address = bdat.Scan0.ToInt32();
|
|||
|
byte[] bitmapData = new byte[bdat.Stride * bdat.Height];
|
|||
|
Marshal.Copy( new IntPtr( address ), bitmapData, 0, bitmapData.Length );
|
|||
|
//bw.Write( (uint)m_main_avi_header.dwSuggestedBufferSize );
|
|||
|
bw.Write( "BM".ToCharArray() );
|
|||
|
bw.Write( m_bitmapsize );
|
|||
|
bw.Write( (uint)0x0 );
|
|||
|
bw.Write( (uint)0x36 );
|
|||
|
BITMAPINFOHEADER bih = new BITMAPINFOHEADER(); //(BITMAPINFOHEADER)Marshal.PtrToStructure( Marshal.AllocHGlobal( sizeof( BITMAPINFOHEADER ) ), typeof( BITMAPINFOHEADER ) );
|
|||
|
bih.biSize = (uint)(Marshal.SizeOf( bih ));
|
|||
|
bih.biWidth = bdat.Width;
|
|||
|
bih.biHeight = bdat.Height;
|
|||
|
bih.biPlanes = 1;
|
|||
|
bih.biBitCount = m_pix_fmt == PixelFormat.Format24bppRgb ? (short)24 : (short)32;
|
|||
|
bih.biCompression = 0;//BI_RGB
|
|||
|
bih.biSizeImage = (uint)(bdat.Stride * bdat.Height);
|
|||
|
bih.biXPelsPerMeter = 0;
|
|||
|
bih.biYPelsPerMeter = 0;
|
|||
|
bih.biClrUsed = 0;
|
|||
|
bih.biClrImportant = 0;
|
|||
|
bih.Write( bw );
|
|||
|
bw.Write( bitmapData, 0, bitmapData.Length );
|
|||
|
//const int _BUF_LEN = 512;
|
|||
|
byte[] buf = new byte[m_bitmapsize + 6];
|
|||
|
bw.BaseStream.Seek( 0, SeekOrigin.Begin );
|
|||
|
int len = bw.BaseStream.Read( buf, 0, (int)(m_bitmapsize + 6) );
|
|||
|
if ( len > 0 ) {
|
|||
|
m_stream.BeginWrite( buf, 0, len, null, null );
|
|||
|
}
|
|||
|
m_stream.Flush();
|
|||
|
bw.Close();
|
|||
|
|
|||
|
bmp.UnlockBits( bdat );
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private void WriteFourCC( string value ) {
|
|||
|
byte[] b = new byte[4];
|
|||
|
for ( int i = 0; i < 4; i++ ) {
|
|||
|
b[i] = (byte)value[i];
|
|||
|
}
|
|||
|
m_stream.Write( b, 0, 4 );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private void Write4Byte( uint value ) {
|
|||
|
byte[] b;
|
|||
|
b = BitConverter.GetBytes( value );
|
|||
|
if ( !BitConverter.IsLittleEndian ) {
|
|||
|
Array.Reverse( b );
|
|||
|
}
|
|||
|
m_stream.Write( b, 0, 4 );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public void Close() {
|
|||
|
if ( m_stream != null ) {
|
|||
|
#if !TEST
|
|||
|
m_stream.Disconnect();
|
|||
|
#endif
|
|||
|
m_stream.Close();
|
|||
|
}
|
|||
|
if ( m_ffmpeg != null ) {
|
|||
|
if ( m_ffmpeg.IsAlive ) {
|
|||
|
m_ffmpeg.Abort();
|
|||
|
while ( m_ffmpeg.IsAlive ) {
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public void Open( uint scale, uint rate, ulong frames, PixelFormat pix_fmt ) {
|
|||
|
if ( m_stream != null ) {
|
|||
|
m_stream.Close();
|
|||
|
}
|
|||
|
#if TEST
|
|||
|
m_stream = new FileStream( "test.out.avi", FileMode.Create );
|
|||
|
#else
|
|||
|
m_stream = new NamedPipeServerStream( _PIPE_NAME, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.None, 1, 1 );
|
|||
|
#endif
|
|||
|
m_scale = scale;
|
|||
|
m_rate = rate;
|
|||
|
m_frames = frames;
|
|||
|
|
|||
|
m_main_avi_header.dwMicroSecPerFrame = (uint)(1.0e6 * (double)scale / (double)rate);// ! 1秒は10^6μ秒
|
|||
|
m_main_avi_header.dwReserved1 = 0;
|
|||
|
m_main_avi_header.dwFlags = 2064;
|
|||
|
m_main_avi_header.dwInitialFrames = 0;
|
|||
|
m_main_avi_header.dwStreams = 0;
|
|||
|
m_main_avi_header.dwScale = scale;
|
|||
|
m_main_avi_header.dwRate = rate;
|
|||
|
m_main_avi_header.dwStart = 0;
|
|||
|
m_main_avi_header.dwLength = 0;
|
|||
|
m_main_avi_header.dwTotalFrames = (uint)m_frames;
|
|||
|
|
|||
|
m_pix_fmt = pix_fmt;
|
|||
|
if ( m_pix_fmt != PixelFormat.Format24bppRgb && m_pix_fmt != PixelFormat.Format32bppArgb ) {
|
|||
|
throw new ApplicationException( "pixel format not supported" );
|
|||
|
}
|
|||
|
#if !TEST
|
|||
|
m_ffmpeg = new Thread( new ThreadStart( FFmpegEnc ) );
|
|||
|
m_ffmpeg.Start();
|
|||
|
m_stream.WaitForConnection();
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private void FFmpegEnc() {
|
|||
|
Thread.Sleep( 1000 );
|
|||
|
Process client = new Process();
|
|||
|
client.StartInfo.FileName = "ffmpeg";
|
|||
|
|
|||
|
// windowsの場合
|
|||
|
client.StartInfo.Arguments = @"-f image2pipe -vcodec bmp -i \\.\pipe\" + _PIPE_NAME + " -isync -an -f avi -y test.avi";
|
|||
|
|
|||
|
// その他
|
|||
|
// client.StartInfo.Arguments = @"-i " + _PIPE_NAME + " -y test.mp3";
|
|||
|
|
|||
|
client.StartInfo.RedirectStandardOutput = true;
|
|||
|
client.StartInfo.UseShellExecute = false;
|
|||
|
client.Start();
|
|||
|
StreamReader sr = client.StandardOutput;
|
|||
|
string line = "";
|
|||
|
while ( (line = sr.ReadLine()) != null ) {
|
|||
|
Console.WriteLine( line );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
#endif
|