如何处理视频文件 ( 积分: 200 )

  • 主题发起人 主题发起人 big_hero2000
  • 开始时间 开始时间
B

big_hero2000

Unregistered / Unconfirmed
GUEST, unregistred user!
做到将视频文件的一部分(可以自定义)剪切形成新的视频文件
 
做到将视频文件的一部分(可以自定义)剪切形成新的视频文件
 
得自己分析文件格式
用dshow做简单的多
 
转载的
VCD视频文件DAT格式程序编程
DAT格式的文件其实属于MPEG1文件.它是在纯MPEG数据的基础上加入了一些控制信息组成的.DAT文件的结构我们可以大概的这样认为:DAT文件=DAT文件头+DAT数据.而纯MPEG文件是没有那个头的.
VCD切割程序网上有很多,大部分都是老外写的,而且一般都要收注册费.实际上,如果我们熟识DAT格式的话,完全 可以自己写一个出来.
在DAT文件中,你能经常找到字符串000001ba,但是在它之前,你还能发现好多个字节.它们是几个近乎类似的字节.而且共有的12~13个字节是 00 ff ff ff ff ff ff ff ff ff ff ff 00,我们称它为DAT头吧.这里有解码器所需要的信息,如果是软件解压,他们不是必须的.紧跟其后的是时间戳,如果你够细心,你会发现每一桢得这几个字节是略微有点变化的,变化规律呢?仔细看看,好像跟时间有关啊,呵呵......如果我们现在称以一个DAT头开始,终结于另一个DAT头之间的数据称为一帧,你会发现,DAT的每一帧的长度是固定的,是2352个字节.对于DAT文件,影片时间的长度与文件的大小是有关系的.在DAT中,每秒种将播放75个帧,也就是说每秒播放的字节数是2352*75个字节.
所以,如果我们要切割一个DAT文件中30秒钟到70秒钟之间的内容组成一个新的DAT文件的话,实际上要做的工作如下:先把整个文件头取下来,然后把30秒钟到70秒钟之间的内容添加在其后面即可.其中30秒开始的位置等于DAT头内容大小+2352*75*30,只要SEEK到那个位置开始切割40秒钟的内容即可.(也就是2352*75*40字节.整个新文件的大小为DAT头大小加上2352*75*40字节.
好了.现在只要解决如何找到那个DAT文件的头位置即可.怎么找呢?在整个DAT文件中搜索,找到一个000001BB即可.找到这个位置再加上2352*2字节就是文件头了.有了这些资料,我们已经可以开始写一个DAT切割程序了.全部代码如下:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, MPlayer, ExtCtrls, ComCtrls;

type
TForm1 = class(TForm)
OpenDialog1: TOpenDialog;
GroupBox1: TGroupBox;
Bt_Open: TButton;
Label_Filename: TLabel;
Label_FileSize: TLabel;
Label_VcdTime: TLabel;
GroupBox2: TGroupBox;
StatusBar1: TStatusBar;
Edit_Start: TEdit;
Label1: TLabel;
Label2: TLabel;
Edit_End: TEdit;
Edit_Save1: TEdit;
Bt_Save: TButton;
Bt_Cut: TButton;
Label3: TLabel;
SaveDialog1: TSaveDialog;
procedure Bt_OpenClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Bt_SaveClick(Sender: TObject);
procedure Bt_CutClick(Sender: TObject);
private
iVcdTime:integer;
function GetFileSize(const FileName: string): LongInt;
function GetPacketHead(FileName:String):integer;//查找Dat文件头
function My_CutMpegFile(SourceFile,DestFile:String;StartTime,TimeLength:integer):Boolean;
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
implementation
{$R *.DFM}
function TForm1.GetFileSize(const FileName: string): LongInt;
var
SearchRec: TSearchRec;
begin
if FindFirst(ExpandFileName(FileName), faAnyFile, SearchRec) = 0 then
Result := SearchRec.Size
else Result := 0;
end;
function TForm1.GetPacketHead(FileName:String):integer;
const FORMAT_DATALEN=512*1024;
var
FileStream:TFileStream;
FormatStrings,StringsStream:TStringStream;
iPos:integer;
Mpg1Format:array[1..4]of byte;
iResult:integer;
begin
if not(FileExists(FileName)) then
begin
Result:=$10184;
Exit;
end;
FileStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyNone);
if FileStream.Size<FORMAT_DATALEN then
begin
Result:=$10184+8+2352*2;
Exit;
end;
StringsStream:=TStringStream.Create('');
StringsStream.CopyFrom(FileStream,FORMAT_DATALEN);
FileStream.Free;

FormatStrings:=TStringStream.Create('');
Mpg1Format[1]:=$00;
Mpg1Format[2]:=$00;
Mpg1Format[3]:=$01;
Mpg1Format[4]:=$bb;
FormatStrings.Write(Mpg1Format,Sizeof(Mpg1Format));
iPos:=Pos(FormatStrings.DataString,StringsStream.DataString);
FormatStrings.Free;
StringsStream.Free;
if iPos<=0 then
iResult:=$10184+8+2352*2
else
iResult:=iPos-1+8+2352*2;
Result:=iResult;
end;
function TForm1.My_CutMpegFile(SourceFile,DestFile:String;StartTime,TimeLength:integer):Boolean;
const MyTimeFramSize=2352*75;//每秒钟176400字节
var
MyHeardSize:integer;
MyMpegFile:TFileStream;
MyMemFile:TMemoryStream;

begin
Result:=True;
MyHeardSize:=GetPacketHead(SourceFile);
MyMpegFile:=TFileStream.Create(SourceFile,fmOpenRead or fmShareDenyNone);
MyMemFile:=TMemoryStream.Create;
try
try
MyMemFile.CopyFrom(MyMpegFile,MyHeardSize);
MyMpegFile.Seek(MyHeardSize+MyTimeFramSize*StartTime,soFromBeginning);
MyMemFile.CopyFrom(MyMpegFile,MyTimeFramSize*TimeLength);
MyMemFile.SaveToFile(DestFile);
finally
MyMemFile.Free;
MyMpegFile.Free;
end;
except
Result:=False;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
iVcdTime:=0;
end;
procedure TForm1.Bt_OpenClick(Sender: TObject);
var
MyFileSize:Longint;
iTime:integer;
begin
if OpenDialog1.Execute then
begin
Label_Filename.Caption:=OpenDialog1.FileName;
MyFileSize:=GetFileSize(OpenDialog1.FileName);
iTime:=Trunc((MyFileSize-(GetPacketHead(Label_Filename.Caption)))/(75*2352));
iVcdTime:=iTime;
Label_FileSize.Caption:='文件大小:'+IntToStr(MyFileSize)+'字节';
Label_VcdTime.Caption:='估计总长度:'+IntToStr(iTime)+'秒钟';
Edit_End.Text:=IntToStr(iTime);
end;
end;
procedure TForm1.Bt_SaveClick(Sender: TObject);
begin
if SaveDialog1.Execute then Edit_Save1.Text:=SaveDialog1.FileName;
end;

procedure TForm1.Bt_CutClick(Sender: TObject);
var
iStart,iEnd,Code:integer;
begin
if Not FileExists(Label_Filename.Caption) then
begin
Application.MessageBox('源文件不存在,请重新选择!',Pchar(Application.Title),MB_ICONINFORMATION+MB_OK);
Exit;
end;
if Edit_Save1.Text='' then
begin
Application.MessageBox('请先选择目标文件名称!',Pchar(Application.Title),MB_ICONINFORMATION+MB_OK);
Exit;
end;
if FileExists(Edit_Save1.Text) then
if(Application.MessageBox('目标文件已经存在,您要覆盖它吗?', Pchar(Application.Title), MB_YESNO +MB_ICONQUESTION) = IDNO)
then Exit;
Val(Edit_Start.Text,iStart,Code);
if Code<>0 then
begin
Application.MessageBox('开始时间必须为整数,请重新输入!',Pchar(Application.Title),MB_ICONINFORMATION+MB_OK);
Exit;
end;
Val(Edit_End.Text,iEnd,Code);
if Code<>0 then
begin
Application.MessageBox('时间长度必须为整数,请重新输入!',Pchar(Application.Title),MB_ICONINFORMATION+MB_OK);
Exit;
end;
if iStart<0 then
begin
Application.MessageBox('开始时间必须为正整数,请重新输入!',Pchar(Application.Title),MB_ICONINFORMATION+MB_OK);
Exit;
end;
if iStart>=iVcdTime then
begin
Application.MessageBox('开始时间不能大于或等于文件总长度,请重新输入!',Pchar(Application.Title),MB_ICONINFORMATION+MB_OK);
Exit;
end;
if iEnd>iVcdTime then
begin
Application.MessageBox('时间长度不能大于文件总长度,请重新输入!',Pchar(Application.Title),MB_ICONINFORMATION+MB_OK);
Exit;
end;
if iEnd<=0 then
begin
Application.MessageBox('时间长度必须大于0,请重新输入!',Pchar(Application.Title),MB_ICONINFORMATION+MB_OK);
Exit;
end;
if ((iStart-iEnd)>=iVcdTime) or ((iEnd-iStart)>=iVcdTime) or(((iEnd+iStart)>iVcdTime)) then
begin
Application.MessageBox('实际时间不能大于或等于文件总长度,请重新输入!',Pchar(Application.Title),MB_ICONINFORMATION+MB_OK);
Exit;
end;
My_CutMpegFile(Label_Filename.Caption,Edit_Save1.Text,iStart,iEnd);
Application.MessageBox('切割完毕!',Pchar(Application.Title),MB_ICONINFORMATION+MB_OK);
end;

end.
 
yostgxf,请问对Mpeg,Avi文件如何处理呢?
 
yostgxf,非常感谢您的答案,我还有一个问题,如果合并的话如何处理。
 
后退
顶部