понеділок, 2 червня 2014 р.

FFMBC_02: Making Screencaps

(*
    tutorial01.c

    This tutorial was written by Stephen Dranger (dranger@gmail.com).

    Conversion to Delphi by Oleksandr Nazaruk (mail@freehand.com.ua)
    Tested on Windows 8.1 64bit rus, compiled with Delphi XE5

    A small sample program that shows how to use libavformat and libavcodec to
    read video from a file.

    Run using

    tutorial01 myvideofile.mpg

    to write the first five frames from "myvideofile.mpg" to disk in BMP
    format.
*)

program tutorial01;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  System.Classes,
  Winapi.Windows,
  VCL.Graphics,
  avcodec in '../FFmbc-0.7-rc8/libavcodec/avcodec.pas',
  avformat in '../FFmbc-0.7-rc8/libavformat/avformat.pas',
  avio in '../FFmbc-0.7-rc8/libavformat/avio.pas',
  avutil in '../FFmbc-0.7-rc8/libavutil/avutil.pas',
  opt in '../FFmbc-0.7-rc8/libavutil/opt.pas',
  rational in '../FFmbc-0.7-rc8/libavutil/rational.pas',
  imgutils in '../FFmbc-0.7-rc8/libavutil/imgutils.pas',
  fifo in '../FFmbc-0.7-rc8/libavutil/fifo.pas',
  file_ in '../FFmbc-0.7-rc8/libavutil/file_.pas',
  ctypes in '../FFmbc-0.7-rc8/ctypes.pas',
  swscale in '../FFmbc-0.7-rc8/libswscale/swscale.pas',
  avdevice in '../FFmbc-0.7-rc8/libavdevice/avdevice.pas',
  postprocess in '../FFmbc-0.7-rc8/libpostproc/postprocess.pas';

procedure SaveFrame(pFrameRGB: PAVFrame; width: integer; height: integer; iFrame: integer);
var
  bmp: TBitmap;
  i: integer;
begin
  bmp := TBitmap.Create;
  try
    bmp.PixelFormat := pf32bit;
    bmp.Width := width;
    bmp.Height := height;

    for i := 0 to bmp.Height - 1 do
      CopyMemory ( bmp.ScanLine[i], pointer(integer(pFrameRGB.data[0]) + bmp.Width * 4 * i), bmp.Width * 4);

    bmp.SaveToFile(format('frame_%d.bmp', [iFrame]));
  finally
    bmp.free;
  end;
end;

var
  i, videoStream  : integer;
  src_filename    : ansistring;
  pFormatCtx      : PAVFormatContext = nil;
  pCodecCtx       : PAVCodecContext = nil;
  pCodec          : PAVCodec = nil;
  optionsDict     : PAVDictionary = nil;
  pFrame          : PAVFrame = nil;
  pFrameRGB       : PAVFrame = nil;
  packet          : TAVPacket;
  frameFinished   : integer;
  numBytes        : integer;
  buffer          : pcuint8 = nil;
  sws_ctx         : PSwsContext = nil;

begin
  try
    if (ParamCount < 1) then
    begin
      writeln('Please provide a movie file');
      exit;
    end;

    src_filename:=(AnsiString(ParamStr(1)));

    // Register all formats and codecs
    av_register_all();

    // Open video file
    if (avformat_open_input(@pFormatCtx, PAnsiChar(src_filename), nil, nil)<>0) then
    begin
      writeln(format('Could not open source file %s', [src_filename]));
      exit;
    end;

    // Retrieve stream information
    if avformat_find_stream_info(pFormatCtx , nil) < 0 then
    begin
      writeln(format('Could not find stream information', []));
      exit;
    end;

    // Dump information about file onto standard error
    av_dump_format(pFormatCtx, 0, PAnsiChar(src_filename), 0);

    // Find the first video stream
    videoStream:=-1;
    for i:=0 to pFormatCtx.nb_streams-1 do
    begin
      if pFormatCtx.streams^.codec.codec_type =  AVMEDIA_TYPE_VIDEO then
      begin
        videoStream := i;
        // Get a pointer to the codec context for the video stream
        pCodecCtx:=pFormatCtx.streams^.codec;
        break;
      end;
      inc(pFormatCtx.streams);
    end;

    if videoStream=-1 then
    begin
      writeln('Didn''t find a video stream');
      exit;
    end;

    // Find the decoder for the video stream
    pCodec:=avcodec_find_decoder(pCodecCtx.codec_id);
    if not assigned(pCodec) then
    begin
      writeln('Unsupported codec!');
      exit;
    end;

    // Open codec
    if avcodec_open2(pCodecCtx, pCodec, @optionsDict)<0 then
    begin
      writeln('Could not open codec');
      exit;
    end;

    // Allocate video frame
    pFrame:=avcodec_alloc_frame;

    // Allocate an AVFrame structure
    pFrameRGB:=avcodec_alloc_frame();
    if not assigned(pFrameRGB) then
    begin
      writeln('Could not allocate AVFrame structure');
      exit;
    end;

    // Determine required buffer size and allocate buffer
    numBytes:=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx.width,  pCodecCtx.height);
    buffer:=av_malloc(numBytes*sizeof(pcuint8));

    sws_ctx :=
    sws_getContext
    (
        pCodecCtx.width,
        pCodecCtx.height,
        pCodecCtx.pix_fmt,
        pCodecCtx.width,
        pCodecCtx.height,
        PIX_FMT_RGB32,
        SWS_BILINEAR,
        nil,
        nil,
        nil
    );

    // Assign appropriate parts of buffer to image planes in pFrameRGB
    // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
    // of AVPicture
    avpicture_fill(PAVPicture(pFrameRGB), buffer, PIX_FMT_RGB32, pCodecCtx.width, pCodecCtx.height);

    // Read frames and save first five frames to disk
    i:=0;
    while(av_read_frame(pFormatCtx, packet)>=0) do
    begin
      // Is this a packet from the video stream?
      if(packet.stream_index=videoStream) then
      begin
        // Decode video frame
        avcodec_decode_video2(pCodecCtx, pFrame, frameFinished, @packet);

        // Did we get a video frame?
        if frameFinished>0 then
        begin
         // Convert the image from its native format to RGB
          sws_scale
          (
            sws_ctx,
            @pFrame.data,
            @pFrame.linesize,
            0,
            pCodecCtx.height,
            @pFrameRGB.data,
            @pFrameRGB.linesize
          );

         // Save the frame to disk
          inc(i);
         if(i<=5)  then
          begin
           SaveFrame(pFrameRGB, pCodecCtx.width, pCodecCtx.height, i);
          end;
        end;
        // Free the packet that was allocated by av_read_frame
        av_free_packet(@packet);
      end;
    end;

    // Free the RGB image
    av_free(buffer);
    av_free(pFrameRGB);

    // Free the YUV frame
    av_free(pFrame);

    // Close the codec
    avcodec_close(pCodecCtx);

    // Close the video file
    av_close_input_file(pFormatCtx);

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Stand: 
  • Windows 8.1 Enterprise 64Bit Rus
  • Delphi XE5
Links: 
  • Dranger tutorial01 is ffmpeg and SDL Tutorial or How to Write a Video Player in Less Than 1000 Lines

Немає коментарів:

Дописати коментар