(** This module contains decoders and encoders for audio, video and subtitle codecs. *)

open Avutil

type 'a params
type 'media decoder
type 'media encoder


(** Packet. *)
module Packet : sig
  (** Packet type *)
  type 'a t

  (** Parser type *)
  type 'a parser

  (** Return the size of the packet. *)
  val get_size : 'a t -> int

  (** Return the stream index of the packet. *)
  val get_stream_index : 'a t -> int

  (** Set the stream index of the packet. *)
  val set_stream_index : 'a t -> int -> unit

  (** Return a fresh bytes array containing a copy of packet datas. *)
  val to_bytes : 'a t -> bytes

  val parse_data : 'a parser -> ('a t -> unit) -> data -> unit
  (** [Avcodec.Packet.parse_data parser f data] applies function [f] to the parsed packets frome the [data] array according to the [parser] configuration.
    @raise Error if the parsing failed. *)

  val parse_bytes : 'a parser -> ('a t -> unit) -> bytes -> int -> unit
  (** Same as {!Avcodec.Packet.parse_data} with bytes array. *)

end


(** Audio codecs. *)
module Audio : sig
  (** Main types for audio codecs. *)
  type 'a t

  val find_encoder : string -> [`Encoder] t
  (** Find an encoder from its name.
      @raise Error if the codec is not found or is not an audio codec. *)

  val find_decoder : string -> [`Decoder] t
  (** Find a decoder from its name.
      @raise Error if the codec is not found or is not an audio codec. *)

  (** Return the list of supported channel layouts of the codec. *)
  val get_supported_channel_layouts : _ t -> Avutil.Channel_layout.t list
      
  val find_best_channel_layout : _ t -> Avutil.Channel_layout.t -> Avutil.Channel_layout.t
  (** [Avcodec.Audio.find_best_channel_layout codec default] return the best channel layout of the [codec] codec or the [default] value if the codec has no channel layout. *)

  (** Return the list of supported sample formats of the codec. *)
  val get_supported_sample_formats : _ t -> Avutil.Sample_format.t list
      
  val find_best_sample_format : _ t -> Avutil.Sample_format.t -> Avutil.Sample_format.t
  (** [Avcodec.Audio.find_best_sample_format codec default] return the best sample format of the [codec] codec or the [default] value if the codec has no sample format. *)

  (** Return the list of supported sample rates of the codec. *)
  val get_supported_sample_rates : _ t -> int list
      
  val find_best_sample_rate : _ t -> int -> int
  (** [Avcodec.Audio.find_best_sample_rate codec default] return the best sample rate of the [codec] codec or the [default] value if the codec has no sample rate. *)

  val create_parser : [`Decoder] t -> audio Packet.parser
  (** [Avcodec.Audio.create_parser codec] create an audio packet parser.
      @raise Error if the parser creation failed. *)

  val create_decoder : [`Decoder] t -> audio decoder
  (** [Avcodec.Audio.create_decoder codec] create an audio decoder.
      @raise Error if the decoder creation failed. *)

  val create_encoder : ?bit_rate:int -> [`Encoder] t -> audio encoder
  (** [Avcodec.Audio.create_encoder ~bit_rate:bit_rate codec] create an audio encoder.
      @raise Error if the encoder creation failed. *)

  (** Audio codec ids. Careful: different codecs share the same ID, e.g. aac and libfdk_aac *)
  type id = Codec_id.audio

  (** Return the name of the codec ID. *)
  val string_of_id : id -> string

  (** Return the ID (class) of a codec. *)
  val get_id : _ t -> id

  (** Return the id of the codec params. *)
  val get_params_id : audio params -> id

  (** Return the channel layout set for the codec params. *)
  val get_channel_layout : audio params -> Avutil.Channel_layout.t

  (** Returns the number of channels set for the codec params. *)
  val get_nb_channels : audio params -> int

  (** Returns the sample format set for the codec params. *)
  val get_sample_format : audio params -> Avutil.Sample_format.t

  (** Returns the bit rate set for the codec params. *)
  val get_bit_rate : audio params -> int

  (** Returns the sample rate set for the codec. *)
  val get_sample_rate : audio params -> int
end

(** Video codecs. *)
module Video : sig
  (** Main types for video codecs. *)
  type 'a t

  val find_encoder : string -> [`Encoder] t
  (** Find an encoder from its name.
      @raise Error if the codec is not found or is not an audio codec. *)

  val find_decoder : string -> [`Decoder] t
  (** Find a decoder from its name.
      @raise Error if the codec is not found or is not an audio codec. *)

  (** Return the list of supported frame rates of the codec. *)
  val get_supported_frame_rates : _ t -> Avutil.rational list
      
  val find_best_frame_rate : _ t -> Avutil.rational -> Avutil.rational
  (** [Avcodec.Video.find_best_frame_rate codec default] return the best frame rate of the [codec] codec or the [default] value if the codec has no frame rate. *)

  (** Return the list of supported pixel formats of the codec. *)
  val get_supported_pixel_formats : _ t -> Avutil.Pixel_format.t list
      
  val find_best_pixel_format : _ t -> Avutil.Pixel_format.t -> Avutil.Pixel_format.t
  (** [Avcodec.Video.find_best_pixel_format codec default] return the best pixel format of the [codec] codec or the [default] value if the codec has no pixel format. *)

  val create_parser : [`Decoder] t -> video Packet.parser
  (** [Avcodec.Video.create_parser codec] create an video packet parser.
      @raise Error if the parser creation failed. *)

  val create_decoder : [`Decoder] t -> video decoder
  (** [Avcodec.Video.create_decoder codec] create a video decoder.
      @raise Error if the decoder creation failed. *)

  val create_encoder : ?bit_rate:int -> ?frame_rate:int -> [`Encoder] t -> video encoder
  (** [Avcodec.Video.create_encoder ~bit_rate:bit_rate codec] create a video encoder.
      @raise Error if the encoder creation failed. *)

  (** Video codec ids. Careful: different codecs share the same ID, e.g. aac and libfdk_aac *)
  type id = Codec_id.video

  (** Return the name of the codec. *)
  val string_of_id : id -> string

  (** Return the ID (class) of a codec. *)
  val get_id : _ t -> id

  (** Return the id of the codec params. *)
  val get_params_id : video params -> id

  (** Returns the width set for the codec params. *)
  val get_width : video params -> int

  (** Returns the height set for the codec params. *)
  val get_height : video params -> int

  (** Returns the sample aspect ratio set for the codec params. *)
  val get_sample_aspect_ratio : video params -> Avutil.rational

  (** Returns the pixel format set for the codec params. *)
  val get_pixel_format : video params -> Avutil.Pixel_format.t

  (** Returns the bit rate set for the codec. *)
  val get_bit_rate : video params -> int
end

(** Subtitle codecs. *)
module Subtitle : sig
  (** Main subtitle types. *)
  type 'a t

  val find_encoder : string -> [`Encoder] t
  (** Find an encoder from its name.
      @raise Error if the codec is not found or is not an audio codec. *)

  val find_decoder : string -> [`Decoder] t
  (** Find a decoder from its name.
      @raise Error if the codec is not found or is not an audio codec. *)

  (** Subtitle codec ids. Careful: different codecs share the same ID, e.g. aac and libfdk_aac *)
  type id = Codec_id.subtitle

  (** Return the name of the codec. *)
  val string_of_id : id -> string

  (** Return the ID (class) of a codec. *)
  val get_id : _ t -> id

  (** Return the id of the codec params. *)
  val get_params_id : subtitle params -> id
end


val decode : 'media decoder -> ('media frame -> unit) -> 'media Packet.t -> unit
(** [Avcodec.decode decoder f packet] applies function [f] to the decoded frames frome the [packet] according to the [decoder] configuration.
    @raise Error if the decoding failed. *)

val flush_decoder : 'media decoder -> ('media frame -> unit) -> unit
(** [Avcodec.flush_decoder decoder f] applies function [f] to the decoded frames frome the buffered packets in the [decoder].
    @raise Error if the decoding failed. *)

val encode : 'media encoder -> ('media Packet.t -> unit) -> 'media frame -> unit
(** [Avcodec.encode encoder f frame] applies function [f] to the encoded packets from the [frame] according to the [encoder] configuration.
    @raise Error if the encoding failed. *)

val flush_encoder : 'media encoder -> ('media Packet.t -> unit) -> unit
(** [Avcodec.flush_encoder encoder] applies function [f] to the encoded packets from the buffered frames in the [encoder].
    @raise Error if the encoding failed. *)
