(* 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
Немає коментарів:
Дописати коментар