我在我的电脑里的e盘,把所有的视频文件的后缀名都统一改为.mpeg格式.但是我现在想恢复到原来的格式,对于原来的格式,我也不清楚,听说可以根据文件在硬盘的头文件信息,可以恢复.请问怎么用delphi实现啊,请那位大虾帮忙啊,小弟感激不尽!!1

解决方案 »

  1.   

    RMVB格式的文件头四个字节固定是.RM
      

  2.   

    给个例子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;interfaceuses
    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.   可能大家还记得我曾经写过一篇<<用Delphi在局域网中实现网上影院>>,就是在局部网内一台电脑播放视频文件整个局部网的电脑都可以收到.那个采用的是隐形动态共享的办法.但是那个方法有个致命的弱点,就是当播放的是光盘文件而不是磁盘文件的时候,当几个人同时访问光驱就不行了.所以那个是取巧的方法.真正的方法是采用流.或者在数据头伪造Mediaplay Server服务器.这样一来无论是磁盘文件还是光盘文件,实际上都是服务器一台电脑读数据而已,就不会发生上面的情况了.具体程序可以在我的主页http://www.138soft.com下载.但是如果对这些不熟练怎么办?哈哈,你还是可以采用取巧的方法:服务端开两个线程,一个发送文件头,另外一个发送数据.客户端也开两个线程,一个接收数据保存为文件,另外一个播放.比如说每个文件为4MB,接收完第一个后开始播放同时继续接收第二个.播放完第一个就删除并播放第二个文件.实际上,早期的DVB就是这样做的.
      

  3.   

    用一个编码查看器(AVIcodec)可以查看文件信息