package theora

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file theora.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
(*
 * Copyright 2007-2011 Savonet team
 *
 * This file is part of ocaml-theora.
 *
 * ocaml-theora is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * ocaml-theora is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ocaml-theora; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *)

(**
  * Functions for encoding theora files using libtheora.
  *
  * @author Samuel Mimram
  * @author Romain Beauxis
  *)

exception Internal_error
exception Invalid_data
exception Bad_packet
exception Header_not_theora
exception Bad_header
exception Not_implemented
exception Bitstream_version_too_high
exception Unknown_error of int
exception Duplicate_frame
exception Done
exception Not_initialized

let () =
  Callback.register_exception "theora_exn_fault" Internal_error;
  Callback.register_exception "theora_exn_version" Bitstream_version_too_high;
  Callback.register_exception "theora_exn_bad_packet" Bad_packet;
  Callback.register_exception "theora_exn_notformat" Header_not_theora;
  Callback.register_exception "theora_exn_bad_header" Bad_header;
  Callback.register_exception "theora_exn_not_implemented" Not_implemented;
  Callback.register_exception "theora_exn_inval" Invalid_data;
  Callback.register_exception "theora_exn_unknown" (Unknown_error 0);
  Callback.register_exception "theora_exn_dup_frame" Duplicate_frame;
  Callback.register_exception "theora_exn_not_enough_data" Ogg.Not_enough_data;
  Callback.register_exception "theora_exn_end_of_file" End_of_file

external version_string : unit -> string = "ocaml_theora_version_string"

let version_string = version_string ()

external version_number : unit -> int = "ocaml_theora_version_number"

let version_number =
  let n = version_number () in
  (n lsr 16, (n lsr 8) land 0xff, n land 0xff)

type colorspace =
  | CS_unspecified
  | CS_ITU_REC_470M
  | CS_ITU_REC_470BG
  | CS_NSPACES

type pixelformat = PF_420 | PF_reserved | PF_422 | PF_444

type info = {
  frame_width : int;  (** The encoded frame width.  *)
  frame_height : int;  (** The encoded frame height. *)
  picture_width : int;  (** The displayed picture width. *)
  picture_height : int;  (** The displayed picture height. *)
  picture_x : int;  (** The X offset of the displayed picture. *)
  picture_y : int;  (** The Y offset of the displayed picture. *)
  colorspace : colorspace;  (** The color space. *)
  pixel_fmt : pixelformat;  (** The pixel format. *)
  target_bitrate : int;  (** The target bit-rate in bits per second. *)
  quality : int;  (** The target quality level. *)
  keyframe_granule_shift : int;
      (** The amount to shift to extract the last keyframe number from the granule position. *)
  version_major : int;
  version_minor : int;
  version_subminor : int;
  fps_numerator : int;
  fps_denominator : int;
  aspect_numerator : int;
  aspect_denominator : int;
}

external default_granule_shift : unit -> int
  = "ocaml_theora_default_granuleshift"

let default_granule_shift = default_granule_shift ()

type data_buffer =
  (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t

type yuv_buffer = {
  y_width : int;
  y_height : int;
  y_stride : int;
  y : data_buffer;
  u_width : int;
  u_height : int;
  u_stride : int;
  u : data_buffer;
  v_width : int;
  v_height : int;
  v_stride : int;
  v : data_buffer;
}

let encoder_tag = "ocaml-theora by the savonet team (http://savonet.sf.net/)"

external is_keyframe : Ogg.Stream.packet -> int
  = "ocaml_theora_ogg_packet_iskeyframe"

let is_keyframe op =
  match is_keyframe op with 1 -> true | 0 -> false | _ -> raise Invalid_data

module Encoder = struct
  type t

  type settings = {
    keyframe_frequency : int option;
    vp3_compatible : bool option;
    soft_target : bool option;
    buffer_delay : int option;
    speed : int option;
  }

  external create : info -> settings -> (string * string) array -> t
    = "ocaml_theora_encode_init"

  let create info params comments =
    let comments = ("ENCODER", encoder_tag) :: comments in
    create info params (Array.of_list comments)

  external encode_header : t -> Ogg.Stream.stream -> bool
    = "ocaml_theora_encode_header"

  let encode_header enc os =
    let rec f () = if not (encode_header enc os) then f () in
    f ()

  external encode_buffer : t -> Ogg.Stream.stream -> yuv_buffer -> unit
    = "ocaml_theora_encode_buffer"

  let encode_page enc os generator =
    let rec f () =
      try
        let yuv = generator () in
        encode_buffer enc os yuv;
        Ogg.Stream.get_page os
      with Ogg.Not_enough_data -> f ()
    in
    f ()

  external frames_of_granulepos : t -> Int64.t -> Int64.t
    = "ocaml_theora_encoder_frame_of_granulepos"

  external eos : t -> Ogg.Stream.stream -> unit = "ocaml_theora_encode_eos"
end

module Decoder = struct
  type decoder
  type t

  external check : Ogg.Stream.packet -> bool = "caml_theora_check"
  external create : unit -> decoder = "ocaml_theora_create_dec"

  external headerin : decoder -> Ogg.Stream.packet -> info * string array
    = "ocaml_theora_dec_headerin"

  let headerin dec p =
    let info, comments = headerin dec p in
    let vendor, comments =
      match Array.to_list comments with e :: l -> (e, l) | [] -> ("", [])
    in
    let split s =
      try
        let pos = String.index s '=' in
        (String.sub s 0 pos, String.sub s (pos + 1) (String.length s - pos - 1))
      with Not_found -> ("", s)
    in
    (Obj.magic dec, info, vendor, List.map split comments)

  external frames_of_granulepos : t -> Int64.t -> Int64.t
    = "ocaml_theora_decoder_frame_of_granulepos"

  external get_yuv : t -> Ogg.Stream.stream -> yuv_buffer
    = "ocaml_theora_decode_YUVout"
end

module Skeleton = struct
  external fisbone :
    Nativeint.t -> info -> Int64.t -> string -> Ogg.Stream.packet
    = "ocaml_theora_skeleton_fisbone"

  let fisbone ?(start_granule = Int64.zero)
      ?(headers = [("Content-type", "video/theora")]) ~serialno ~info () =
    let concat s (h, v) = Printf.sprintf "%s%s: %s\r\n" s h v in
    let s = List.fold_left concat "" headers in
    fisbone serialno info start_granule s
end