program ffmpeg_sample_player; { .$APPTYPE CONSOLE } {$R *.res} {$include ffmpeg.inc} uses Winapi.Windows, System.SysUtils, System.Classes, SDL, ffmpeglib in '..\..\ffmpeglib.pas', ctypes in '..\..\..\ctypes\ctypes.pas', avformat in '..\..\libavformat\avformat.pas', avio in '..\..\libavformat\avio.pas', avutil in '..\..\libavutil\avutil.pas', buffer in '..\..\libavutil\buffer.pas', dict in '..\..\libavutil\dict.pas', frame in '..\..\libavutil\frame.pas', log in '..\..\libavutil\log.pas', opt in '..\..\libavutil\opt.pas', pixfmt in '..\..\libavutil\pixfmt.pas', rational in '..\..\libavutil\rational.pas', samplefmt in '..\..\libavutil\samplefmt.pas', parseutils in '..\..\libavutil\parseutils.pas', swscale in '..\..\libswscale\swscale.pas', pixdesc in '..\..\libavutil\pixdesc.pas', imgutils in '..\..\libavutil\imgutils.pas', mem in '..\..\libavutil\mem.pas', error in '..\..\libavutil\error.pas', avfilter in '..\..\libavfilter\avfilter.pas', buffersink in '..\..\libavfilter\buffersink.pas', mathematics in '..\..\libavutil\mathematics.pas', libavcodec.avcodec in '..\..\libavcodec\libavcodec.avcodec.pas', buffersrc in '..\..\libavfilter\buffersrc.pas', errno in '..\..\libavutil\errno.pas'; Var err: Integer; filename: AnsiString; format_context: pAVFormatContext = nil; video_stream: Integer; codec_context: pAVCodecContext; codec: pAVCodec; screen: pSDL_Surface; bmp: pSDL_Overlay; img_convert_context: pSwsContext; frame: pAVFrame; packet: TAVPacket; frame_finished: Integer; pict: TAVPicture; rect: TSDL_Rect; event: TSDL_Event; begin try if (ParamCount < 1) then begin WriteLn(Format('Usage: %s filename', [ExtractFileName(ParamStr(0))])); Halt; end; // Register all available file formats and codecs av_register_all(); avformat_network_init(); // Init SDL with video support err := SDL_Init(SDL_INIT_VIDEO); if (err < 0) then begin WriteLn(Format('Unable to init SDL: %s', [SDL_GetError()])); Halt(1); end; // Open video file filename := ParamStr(1); err := avformat_open_input(format_context, PAnsiChar(filename), nil, nil); if (err < 0) then begin WriteLn('ffmpeg: Unable to open input file'); Halt(1); end; // Retrieve stream information err := avformat_find_stream_info(format_context, nil); if (err < 0) then begin WriteLn('ffmpeg: Unable to find stream info'); Halt(1); end; // Dump information about file onto standard error av_dump_format(format_context, 0, PAnsiChar(filename), 0); // Find the first video stream for video_stream := 0 to format_context^.nb_streams - 1 do if (format_context^.streams[video_stream]^.codec^.codec_type = AVMEDIA_TYPE_VIDEO) then break; if (video_stream = format_context^.nb_streams) then begin WriteLn('ffmpeg: Unable to find video stream'); Halt(1); end; codec_context := format_context^.streams[video_stream]^.codec; codec := avcodec_find_decoder(codec_context^.codec_id); err := avcodec_open2(codec_context, codec, nil); if (err < 0) then begin WriteLn('ffmpeg: Unable to open codec'); Halt(1); end; screen := SDL_SetVideoMode(codec_context^.width, codec_context^.height, 0, 0 { SDL_FULLSCREEN } ); if (screen = nil) then begin WriteLn('Couldn''t set video mode'); Halt(1); end; bmp := SDL_CreateYUVOverlay(codec_context^.width, codec_context^.height, SDL_YV12_OVERLAY, screen); img_convert_context := sws_getCachedContext(nil, codec_context^.width, codec_context^.height, codec_context^.pix_fmt, codec_context^.width, codec_context^.height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, nil, nil, nil); if (img_convert_context = nil) then begin WriteLn('Cannot initialize the conversion context'); Halt(1); end; frame := avcodec_alloc_frame(); while (av_read_frame(format_context, packet) >= 0) do begin if (packet.stream_index = video_stream) then begin // Video stream packet avcodec_decode_video2(codec_context, frame, frame_finished, @packet); if (frame_finished <> 0) then begin SDL_LockYUVOverlay(bmp); // Convert frame to YV12 pixel format for display in SDL overlay pByte(pict.data[0]) := pByte(bmp^.pixels[0]); pByte(pict.data[1]) := pByte(bmp^.pixels[2]); // it's because YV12 pByte(pict.data[2]) := pByte(bmp^.pixels[1]); pict.linesize[0] := bmp^.pitches[0]; pict.linesize[1] := bmp^.pitches[2]; pict.linesize[2] := bmp^.pitches[1]; sws_scale(img_convert_context, @frame^.data, @frame^.linesize, 0, codec_context^.height, @pict.data, @pict.linesize); SDL_UnlockYUVOverlay(bmp); rect.x := 0; rect.y := 0; rect.w := codec_context^.width; rect.h := codec_context^.height; SDL_DisplayYUVOverlay(bmp, @rect); end; end; // Free the packet that was allocated by av_read_frame av_free_packet(packet); // Handling SDL events there if SDL_PollEvent(@event) <> 0 then if (event.type_ = SDL_QUITEV) then break; end; sws_freeContext(img_convert_context); // Free the YUV frame av_free(frame); // Close the codec avcodec_close(codec_context); // Close the video file avformat_close_input(&format_context); avformat_network_deinit; // Quit SDL SDL_QUIT(); except on E: Exception do WriteLn(E.ClassName, ': ', E.Message); end; end.