четвер, 5 червня 2014 р.

FFMBC_05: Spawning Threads

(*
    tutorial04.c
    A pedagogical video player that will stream through every video frame as fast as it can
    and play audio (out of sync).

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

    Code based on FFplay, Copyright (c) 2003 Fabrice Bellard,
    and a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)

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

    Run using

    tutorial04 myvideofile.mpg

    to play the video stream on your screen.
*)

program tutorial04;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  System.Classes,
  math,
  SDL2 in '../../../Injest/LIB/SDL/Pascal-SDL-2-Header/SDL2.pas',
  avcodec in '../FFmbc-0.7/libavcodec/avcodec.pas',
  avformat in '../FFmbc-0.7/libavformat/avformat.pas',
  avio in '../FFmbc-0.7/libavformat/avio.pas',
  avutil in '../FFmbc-0.7/libavutil/avutil.pas',
  opt in '../FFmbc-0.7/libavutil/opt.pas',
  rational in '../FFmbc-0.7/libavutil/rational.pas',
  imgutils in '../FFmbc-0.7/libavutil/imgutils.pas',
  fifo in '../FFmbc-0.7/libavutil/fifo.pas',
  file_ in '../FFmbc-0.7/libavutil/file_.pas',
  ctypes in '../FFmbc-0.7/ctypes.pas',
  swscale in '../FFmbc-0.7/libswscale/swscale.pas',
  avdevice in '../FFmbc-0.7/libavdevice/avdevice.pas',
  postprocess in '../FFmbc-0.7/libpostproc/postprocess.pas';

const
  SDL_AUDIO_BUFFER_SIZE     = 1024;
  MAX_AUDIO_FRAME_SIZE      = 192000;

  MAX_AUDIOQ_SIZE           = (5 * 16 * 1024);
  MAX_VIDEOQ_SIZE           = (5 * 256 * 1024);

  USE_AUDIO_DRIVER          = 'directsound';

  FF_ALLOC_EVENT            = (SDL_USEREVENT);
  FF_REFRESH_EVENT          = (SDL_USEREVENT + 1);
  FF_QUIT_EVENT             = (SDL_USEREVENT + 2);

  VIDEO_PICTURE_QUEUE_SIZE  = 1;

type
  PPacketQueue =^TPacketQueue;
  TPacketQueue = record
    first_pkt   : PAVPacketList;
    last_pkt    : PAVPacketList;
    nb_packets  : integer;
    size        : integer;
    mutex       : PSDL_mutex;
    cond        : PSDL_cond;
  end;

  PVideoPicture = ^TVideoPicture;
  TVideoPicture = record
    bmp           : PSDL_texture;
    width, height : integer; (* source height & width *)
    allocated     : integer;
    buffer        : pcuint8;
    pFrameYUV420P : PAVFrame;
  end;

  PVideoState = ^TVideoState;
  TVideoState = record
    pFormatCtx      : PAVFormatContext;
    videoStream     : integer;
    audioStream     : integer;
    audio_st        : PAVStream;
    audioq          : PPacketQueue;
    audio_buf       : array[0..((AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) div 2)] of cuint8;
    audio_buf_size  : cardinal;
    audio_buf_index : cardinal;
    audio_frame     : TAVFrame;
    audio_pkt       : TAVPacket;
    audio_pkt_data  : pcuint8;
    audio_pkt_size  : integer;
    video_st        : PAVStream;
    videoq          : PPacketQueue;

    pictq           : array[0..VIDEO_PICTURE_QUEUE_SIZE] of TVideoPicture;
    pictq_size      : integer;
    pictq_rindex    : integer;
    pictq_windex    : integer;
    pictq_mutex     : PSDL_mutex;
    pictq_cond      : PSDL_cond;

    parse_tid       : PSDL_Thread;
    video_tid       : PSDL_Thread;

    filename        : array[0..1024] of ansichar;
    quit            : boolean;

    io_context      : PAVIOContext;
    sws_ctx         : PSwsContext;
  end;

var
  screen              : PSDL_Window = nil;
  render              : PSDL_renderer = nil;

  (* Since we only have one decoding thread, the Big Struct
   can be global in case we need it. *)
  global_video_state  : PVideoState;



procedure packet_queue_init(var q: PPacketQueue);
begin
  if not assigned(q) then
    new(q);
  fillchar(q^, sizeof(TPacketQueue), #0);
  q.mutex := SDL_CreateMutex();
  q.cond := SDL_CreateCond();
end;

function packet_queue_put(var q: PPacketQueue; pkt: PAVPacket): integer;
var
  pkt1  : PAVPacketList;
begin
  result:=-1;

  if not assigned(pkt) then
    exit;

  if(av_dup_packet(pkt) < 0) then
  begin
    result:=-1;
    exit;
  end;

  pkt1 := av_malloc(sizeof(TAVPacketList));
  if not assigned(pkt1) then
  begin
    result:=-1;
    exit;
  end;

  pkt1^.pkt := pkt^;
  pkt1^.next := nil;

  SDL_LockMutex(q.mutex);
  try

    if not assigned(q.last_pkt) then
      q.first_pkt := pkt1
    else
      q.last_pkt^.next := pkt1;

    q.last_pkt := pkt1;
    inc(q.nb_packets);
    q.size:=q.size+pkt1.pkt.size;
    SDL_CondSignal(q.cond);
  finally
    SDL_UnlockMutex(q.mutex);
  end;

  result:=0;
end;

function packet_queue_get(var q: PPacketQueue; var pkt: TAVPacket; block: integer): integer;
var
  pkt1  : PAVPacketList;
  ret   : integer;
begin
  result:=-1;
  ret:=-1;
  SDL_LockMutex(q.mutex);
  try
    while true do
    begin
      if global_video_state.quit then
      begin
        result:=-1;
        break;
      end;
      pkt1 := q.first_pkt;
      if Assigned(pkt1) then
      begin
        q.first_pkt := pkt1^.next;
        if not assigned(q.first_pkt) then
          q.last_pkt := nil;
        dec(q.nb_packets);
        q.size := q.size-pkt1^.pkt.size;
        pkt := pkt1^.pkt;
        av_free(pkt1);
        ret := 1;
        break;
      end else
      if (block)<=0 then
      begin
        ret := 0;
        break;
      end else begin
        SDL_CondWait(q.cond, q.mutex);
      end;
    end;
  finally
    SDL_UnlockMutex(q.mutex);
  end;

  result:=ret;
end;

function audio_decode_frame(is_: PVideoState): integer;
var
  pkt             : TAVPacket;    /////////// PAVPacket
  len1            : integer;
  data_size       : integer;
  buffer_size     : integer;
begin
  data_size:=0;
  len1:=0;
  pkt:=is_.audio_pkt;

  while True do
  begin
    while (is_.audio_pkt_size > 0) do
    begin
      buffer_size := ((AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) div 2);
      len1 := avcodec_decode_audio3(is_.audio_st.codec, PSmallInt(@is_.audio_buf[0]), buffer_size, @pkt);
      if(len1 <= 0) then
      begin
       (* if error, skip frame *)
       is_.audio_pkt_size := 0;
       break;
      end;
      inc(is_.audio_pkt_data,len1);
      dec(is_.audio_pkt_size,len1);
      inc(data_size, len1);
      if(data_size <= 0) then
      begin
       (* No data yet, get more frames *)
       continue;
      end;
      (* We have data, return it and come back for more later *)
      result:=data_size;
      exit;
    end;
    if assigned(pkt.data) then
      av_free_packet(@pkt);

    if is_.quit then
    begin
      result:=-1;
      exit;
    end;

    if(packet_queue_get(is_.audioq, pkt, 1) < 0) then
    begin
      result:=-1;
      exit;
    end;
    is_.audio_pkt_data := pkt.data;
    is_.audio_pkt_size := pkt.size;
  end;
end;

procedure audio_callback(userdata: Pointer; stream: PUInt8; len: LongInt); cdecl;
var
  is_             : PVideoState;
  audio_size      : integer;
  len1            : integer;
begin
  is_:=PVideoState(userdata);

  while (len > 0) do
  begin
    if(is_.audio_buf_index >= is_.audio_buf_size) then
    begin
      (* We have already sent all our data; get more *)
      audio_size := audio_decode_frame(is_);
      if(audio_size < 0) then
      begin
       (* If error, output silence *)
       is_.audio_buf_size := 1024; // arbitrary?
       fillchar(is_.audio_buf[0], is_.audio_buf_size, #0);
      end else begin
       is_.audio_buf_size := audio_size;
      end;
      is_.audio_buf_index := 0;
    end;
    len1 := is_.audio_buf_size - is_.audio_buf_index;
    if(len1 > len) then
      len1 := len;
    move(is_.audio_buf[is_.audio_buf_index], stream^, len1);
    dec(len, len1);
    inc(stream,len1);
    inc(is_.audio_buf_index,len1);
  end;
end;


function sdl_refresh_timer_cb(interval: cardinal; opaque : Pointer): cardinal; cdecl;
var
  event : TSDL_Event;
begin
  event.type_ := FF_REFRESH_EVENT;
  event.user.data1 := opaque;
  SDL_PushEvent(@event);
  result:=0; (* 0 means stop timer *)
end;

(* schedule a video refresh in 'delay' ms *)
procedure schedule_refresh(is_: PVideoState; delay: integer);
begin
  SDL_AddTimer(delay, @sdl_refresh_timer_cb, is_);
end;


procedure video_display(is_: PVideoState);
var
  vp            : PVideoPicture;
  aspect_ratio  : float;
  w, h, x, y    : integer;
begin

  vp := @is_.pictq[is_.pictq_rindex];
  if assigned(vp.bmp) then
  begin
    if(is_.video_st.codec.sample_aspect_ratio.num = 0) then
    begin
      aspect_ratio := 0;
    end else
    begin
      aspect_ratio := av_q2d(is_.video_st.codec.sample_aspect_ratio) *
     is_.video_st.codec.width / is_.video_st.codec.height;
    end;
    if (aspect_ratio <= 0.0)  then
    begin
      aspect_ratio := is_.video_st.codec.width /is_.video_st.codec.height;
    end;
    h := screen.h;
    w := (round(h * aspect_ratio)) and -3;
    if(w > screen.w) then
    begin
      w := screen.w;
      h := (round(w / aspect_ratio)) and -3;
    end;

    x := (screen.w - w) div 2;
    y := (screen.h - h) div 2;

    SDL_RenderClear(Render);
    SDL_RenderCopy(Render, vp.bmp, nil, nil);
    SDL_RenderPresent(Render);
  end;
end;

procedure video_refresh_timer(userdata: pointer);
var
  is_ : PVideoState;
begin

  is_ := PVideoState(userdata);
  // vp is used in later tutorials for synchronization
  //VideoPicture *vp;

  if assigned(is_.video_st) then
  begin
    if (is_.pictq_size = 0) then
    begin
      schedule_refresh(is_, 1)
    end else
    begin
      //vp = &is->pictq[is->pictq_rindex];
      (* Now, normally here goes a ton of code
     about timing, etc. we're just going to
     guess at a delay for now. You can
     increase and decrease this value and hard code
     the timing - but I don't suggest that ;)
     We'll learn how to do it for real later.
      *)
      schedule_refresh(is_, 80);

      (* show the picture! *)
      video_display(is_);

      (* update queue for next picture! *)
      inc(is_.pictq_rindex);
      if (is_.pictq_rindex = VIDEO_PICTURE_QUEUE_SIZE) then
      begin
       is_.pictq_rindex := 0;
      end;
      SDL_LockMutex(is_.pictq_mutex);
      dec(is_.pictq_size);
      SDL_CondSignal(is_.pictq_cond);
      SDL_UnlockMutex(is_.pictq_mutex);
    end;
  end else
  begin
    schedule_refresh(is_, 100);
  end;
end;

procedure alloc_picture(userdata: pointer);
var
  is_         : PVideoState;
  vp          : PVideoPicture;
  numBytes    : integer;
begin
  is_ := PVideoState(userdata);

  vp := @is_.pictq[is_.pictq_windex];
  if assigned(vp.bmp) then
  begin
    // we already have one make another, bigger/smaller
    SDL_DestroyTexture(vp.bmp);
  end;

  if assigned(vp.pFrameYUV420P) then
  begin
    av_free(vp.pFrameYUV420P);
  end;

  if assigned(vp.buffer) then
  begin
    av_free(vp.buffer);
  end;


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

  // Determine required buffer size and allocate buffer
  numBytes:=avpicture_get_size(is_.video_st.codec.pix_fmt, is_.video_st.codec.width, is_.video_st.codec.height);
  vp.buffer:=av_malloc(numBytes*sizeof(cuint));

  // Assign appropriate parts of buffer to image planes in pFrameYUV420P
  // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
  // of AVPicture
  avpicture_fill(PAVPicture(vp.pFrameYUV420P), vp.buffer, PIX_FMT_YUV420P, is_.video_st.codec.width, is_.video_st.codec.height);

  // Allocate a place to put our YUV image on that screen
  vp.bmp:=SDL_CreateTexture(render, SDL_PIXELFORMAT_YV12, sint32(SDL_TEXTUREACCESS_STREAMING), is_.video_st.codec.width, is_.video_st.codec.height);

  vp.width := is_.video_st.codec.width;
  vp.height := is_.video_st.codec.height;

  SDL_LockMutex(is_.pictq_mutex);
  vp.allocated := 1;
  SDL_CondSignal(is_.pictq_cond);
  SDL_UnlockMutex(is_.pictq_mutex);
end;


function queue_picture(is_: PVideoState; pFrame: PAVFrame): integer;
var
  vp    : PVideoPicture;
  pict  : TAVPicture;
  event : TSDL_Event;
begin

  (* wait until we have space for a new pic *)
  SDL_LockMutex(is_.pictq_mutex);
  while ((is_.pictq_size >= VIDEO_PICTURE_QUEUE_SIZE) and (not is_.quit)) do
  begin
    SDL_CondWait(is_.pictq_cond, is_.pictq_mutex);
  end;

  SDL_UnlockMutex(is_.pictq_mutex);

  if is_.quit then
  begin
    result:=-1;
    exit;
  end;

  // windex is set to 0 initially
  vp := @is_.pictq[is_.pictq_windex];

  (* allocate or resize the buffer! *)
  if ((not assigned(vp.bmp)) or
     (vp.width <> is_.video_st.codec.width) or
     (vp.height <> is_.video_st.codec.height)) then
  begin


    vp.allocated := 0;
    (* we have to do it in the main thread *)
    event.type_ := FF_ALLOC_EVENT;
    event.user.data1 := is_;
    SDL_PushEvent(@event);

    (* wait until we have a picture allocated *)
    SDL_LockMutex(is_.pictq_mutex);
    while ((vp.allocated=0) and (not is_.quit)) do
    begin
      SDL_CondWait(is_.pictq_cond, is_.pictq_mutex);
    end;
    SDL_UnlockMutex(is_.pictq_mutex);
    if is_.quit then
    begin
      result:=-1;
      exit;
    end;
  end;
  (* We have a place to put our picture on the queue *)

  if assigned(vp.bmp) then
  begin


    pict.data[0] := vp.pFrameYUV420P.data[0];
    pict.data[1] := vp.pFrameYUV420P.data[2];
    pict.data[2] := vp.pFrameYUV420P.data[1];

    pict.linesize[0] := vp.pFrameYUV420P.linesize[0];
    pict.linesize[1] := vp.pFrameYUV420P.linesize[2];
    pict.linesize[2] := vp.pFrameYUV420P.linesize[1];


    // Convert the image into YUV format that SDL uses
    sws_scale
    (
    is_.sws_ctx,
    @pFrame.data,
    @pFrame.linesize,
    0,
    is_.video_st.codec.height,
    @pict.data,
    @pict.linesize
    );


    SDL_UpdateTexture(vp.bmp, nil, vp.buffer, is_.video_st.codec.width);

    (* now we inform our display thread that we have a pic ready *)
    inc(is_.pictq_windex);
    if(is_.pictq_windex = VIDEO_PICTURE_QUEUE_SIZE) then
      is_.pictq_windex := 0;

    SDL_LockMutex(is_.pictq_mutex);
    inc(is_.pictq_size);
    SDL_UnlockMutex(is_.pictq_mutex);
  end;
  result:=0;
end;

function video_thread(arg: Pointer): integer;  cdecl;
var
  is_           : PVideoState;
  pkt1          : TAVPacket;
  packet        : TAVPacket;
  frameFinished : integer;
  pFrame        : PAVFrame;
begin
  is_:= PVideoState(arg);
  packet:= pkt1;                  //////////PAVPAcket

  pFrame := avcodec_alloc_frame();

  while true do
  begin
    if(packet_queue_get(is_.videoq, packet, 1) < 0) then
      // means we quit getting packets
      break;

    // Decode video frame
    avcodec_decode_video2(is_.video_st.codec, pFrame, frameFinished, @packet);

    // Did we get a video frame?
    if (frameFinished)>0 then
    begin
      if(queue_picture(is_, pFrame) < 0) then break;
    end;
    av_free_packet(@packet);
  end;
  av_free(pFrame);
  result:=0;
end;



function stream_component_open(var is_: PVideoState; stream_index: integer): integer;
var
  pFormatCtx    : PAVFormatContext;
  codecCtx      : PAVCodecContext;
  codec         : PAVCodec;
  optionsDict   : PAVDictionary;
  wanted_spec   : TSDL_AudioSpec;
  spec          : TSDL_AudioSpec;
  pStreams      : PPAVStream;
  pStream       : PAVStream;
  i             : integer;
begin
  result:=-1;
  pStream :=  nil;
  pFormatCtx := is_.pFormatCtx;

  codecCtx := nil;
  codec := nil;
  optionsDict:= nil;


  if((stream_index < 0) or (stream_index >= pFormatCtx.nb_streams)) then
  begin
    result:=-1;
    exit;
  end;


  // Get a pointer to the codec context for the video stream
  pStreams:=pFormatCtx.streams;
  for i:=0 to pFormatCtx.nb_streams-1 do
  begin
    if i=stream_index then
    begin
      pStream:=pStreams^;
      codecCtx:=pStream.codec;
    end;
    inc(pStreams);
  end;


  if(codecCtx^.codec_type = AVMEDIA_TYPE_AUDIO) then
  begin
    // Set audio settings from codec info
    wanted_spec.freq := codecCtx^.sample_rate;
    wanted_spec.format := AUDIO_S16;
    wanted_spec.channels := codecCtx^.channels;
    wanted_spec.silence := 0;
    wanted_spec.samples := SDL_AUDIO_BUFFER_SIZE;
    wanted_spec.callback := @audio_callback;
    wanted_spec.userdata := is_;

    if(SDL_OpenAudio(@wanted_spec, @spec) <> 0) then
    begin
      writeln(format('SDL_OpenAudio: %s', [SDL_GetError()]));
      //exit;
    end;
  end;

  codec := avcodec_find_decoder(codecCtx.codec_id);
  if ((not assigned(codec)) or (avcodec_open2(codecCtx, codec, @optionsDict)<0)) then
  begin
      writeln('Unsupported codec!');
      exit;
  end;

  case codecCtx.codec_type of
    AVMEDIA_TYPE_AUDIO:
    begin
      is_.audioStream := stream_index;
      is_.audio_st := pStream;
      is_.audio_buf_size := 0;
      is_.audio_buf_index := 0;

      fillchar(is_.audio_pkt, sizeof(is_.audio_pkt), #0);

      packet_queue_init(is_.audioq);
      SDL_PauseAudio(0);
     end;
    AVMEDIA_TYPE_VIDEO:
    begin
      is_.videoStream := stream_index;
      is_.video_st := pStream;

      packet_queue_init(is_.videoq);
      is_.video_tid := SDL_CreateThread(@video_thread, nil, is_);

      is_.sws_ctx :=
      sws_getContext
      (
          is_.video_st.codec.width,
          is_.video_st.codec.height,
          is_.video_st.codec.pix_fmt,
          is_.video_st.codec.width,
          is_.video_st.codec.height,
          PIX_FMT_YUV420P,
          SWS_BILINEAR,
          nil,
          nil,
          nil
      );
    end;
  end;
  result:=0;
end;


function decode_interrupt_cb(opaque: Pointer): integer;
begin
  if (assigned(global_video_state) and (global_video_state.quit)) then
    result:=1 else result:=0;
end;



function decode_thread(arg: pointer): LongInt;  cdecl;
label
  fail;
var
  is_           : PVideoState;
  pFormatCtx    : PAVFormatContext;
  packet        : PAVPacket;
  pkt1          : TAVPacket;
  video_index   : integer;
  audio_index   : integer;
  i             : integer;
  io_dict       : PAVDictionary;
  pStream       : PPAVStream;
  event         : TSDL_Event;

begin
  is_ := PVideoState(arg);

  pFormatCtx:= nil;
  packet := @pkt1;

  video_index := -1;
  audio_index := -1;

  io_dict := nil;


  is_.videoStream := -1;
  is_.audioStream := -1;

  global_video_state := is_;

  if avio_open(is_.io_context, @is_.filename[0], 0)<0 then
  begin
    writeln(format('Unable to open I/O for %s', [ansistring(is_.filename)]));
    result:=-1;
    exit;
  end;

  // Open video file
  if(avformat_open_input(@pFormatCtx, @is_.filename[0], nil, nil)<>0) then
  begin
      writeln(format('Could not open source file %s', [ansistring(is_.filename)]));
      result:=-1;
      exit;
  end;

  is_.pFormatCtx := pFormatCtx;

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

  // Dump information about file onto standard error
  av_dump_format(pFormatCtx, 0, @is_.filename[0], 0);


  // Find the first video stream

   pStream:=pFormatCtx.streams;
   for i:=0 to pFormatCtx.nb_streams-1 do
   begin
      if ((pStream^.codec.codec_type =  AVMEDIA_TYPE_VIDEO) and (video_index<0)) then
      begin
        video_index := i;
      end else
      if ((pStream^.codec.codec_type =  AVMEDIA_TYPE_AUDIO) and (audio_index < 0)) then
      begin
        audio_index := i;
      end;
      inc(pStream);
   end;


  if (audio_index >= 0) then
    stream_component_open(is_, audio_index);

  if(video_index >= 0) then
    stream_component_open(is_, video_index);

  if ((is_.videoStream < 0) or (is_.audioStream < 0)) then
  begin
    writeln(format('%s: could not open codecs', [ansistring(is_.filename)]));
    goto fail;
  end;

  // main decode loop

  while True do
  begin
    if is_.quit then
      break;

    // seek stuff goes here
    if((is_.audioq.size > MAX_AUDIOQ_SIZE) or
       (is_.videoq.size > MAX_VIDEOQ_SIZE)) then
    begin
      SDL_Delay(10);
      continue;
    end;

    if(av_read_frame(is_.pFormatCtx, packet^) < 0) then
    begin
      if(is_.pFormatCtx.pb.error = 0) then
      begin
       SDL_Delay(100); (* no error; wait for user input *)
       continue;
      end else begin
       break;
      end;
    end;
    // Is this a packet from the video stream?
    if(packet.stream_index = is_.videoStream) then
      packet_queue_put(is_.videoq, packet)
    else if(packet.stream_index = is_.audioStream) then
      packet_queue_put(is_.audioq, packet)
    else av_free_packet(@packet);
  end;
  (* all done - wait for it *)
  while (not is_.quit) do
    SDL_Delay(100);


  fail:
  begin
    event.type_ := FF_QUIT_EVENT;
    event.user.data1 := is_;
    SDL_PushEvent(@event);
  end;
  result:=0;
end;


var
  event         : TSDL_event;
  is_           : PVideoState;
  src_filename  : ansistring;
  FAudioDriver  : ansistring;

begin
  try
    new(is_);

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

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

    if SDL_Init(SDL_INIT_VIDEO or SDL_INIT_AUDIO or SDL_INIT_TIMER)<0 then
    begin
      writeln(format('Could not initialize SDL - %s', [SDL_GetError()]));
      exit;
    end;

    // Register all formats and codecs
    av_register_all();

    StrPCopy(is_.filename, src_filename);

    // List audio driver
    //for I := 0 to SDL_GetNumAudioDrivers-1 do
    //  FAudioDriver:=SDL_GetAudioDriver(i);

    // Set audio driver
    FAudioDriver:=USE_AUDIO_DRIVER;
    SDL_AudioInit(PAnsiChar(FAudioDriver));

    // Make a screen to put our video
    screen:=SDL_CreateWindow('Tutorial_04', SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 720, 576, SDL_WINDOW_SHOWN );
    if not assigned(screen) then
    begin
      writeln('SDL: could CreateWindow');
      exit;
    end;
    render := SDL_CreateRenderer(screen, -1, 0);



    is_.pictq_mutex := SDL_CreateMutex();
    is_.pictq_cond := SDL_CreateCond();

    schedule_refresh(is_, 40);

    is_.parse_tid := SDL_CreateThread(@decode_thread, nil, is_);
    if not assigned(is_.parse_tid) then
    begin
      av_free(is_);
      exit;
    end;


    while True do
    begin
      SDL_WaitEvent(@event);
      case event.type_ of
        FF_QUIT_EVENT:
        begin
          break;
        end;
        SDL_QUITEV:
        begin
          is_.quit := true;
          (*
           * If the video has finished playing, then both the picture and
           * audio queues are waiting for more data.  Make them stop
           * waiting and terminate normally.
           *)
          SDL_CondSignal(is_.audioq.cond);
          SDL_CondSignal(is_.videoq.cond);
          SDL_Quit();
          break;
        end;
        FF_ALLOC_EVENT:
        begin
          alloc_picture(event.user.data1);
        end;
        FF_REFRESH_EVENT:
        begin
          video_refresh_timer(event.user.data1);
        end;
      end;
    end;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Stand: 
  • Windows 8.1 Enterprise 64Bit Rus
  • Delphi XE5
Links: 
  • Dranger tutorial04 is ffmpeg and SDL Tutorial or How to Write a Video Player in Less Than 1000 Lines

1 коментар:

  1. Coin Casino: No Deposit Bonus & Free Spins › Coin › coin-casino › no-deposit-casino
    The Coin Casino is a new and gioco digitale innovative online casino created in 2017. Established in 2017, this online casino is open for real players from all over the world. 코인카지노 With great odds sbobet ทางเข้า and

    ВідповістиВидалити