-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathmm_theora.ml
135 lines (128 loc) · 4.67 KB
/
mm_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
(*
* Copyright 2011 The Savonet Team
*
* This file is part of ocaml-mm.
*
* ocaml-mm is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* ocaml-mm 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 Lesser General Public License
* along with ocaml-mm; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* As a special exception to the GNU Library General Public License, you may
* link, statically or dynamically, a "work that uses the Library" with a publicly
* distributed version of the Library to produce an executable file containing
* portions of the Library, and distribute that executable file under terms of
* your choice, without any of the additional requirements listed in clause 6
* of the GNU Library General Public License.
* By "a publicly distributed version of the Library", we mean either the unmodified
* Library as distributed by The Savonet Team, or a modified version of the Library that is
* distributed under the conditions defined in clause 3 of the GNU Library General
* Public License. This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU Library General Public License.
*
*)
open Mm_image
open Mm_video
class reader_of_file fname =
let sync, fd = Ogg.Sync.create_from_file fname in
let rec fill os =
let page = Ogg.Sync.read sync in
try
(* We drop pages which are not for us.. *)
if Ogg.Page.serialno page = Ogg.Stream.serialno os then
Ogg.Stream.put_page os page
with Ogg.Bad_data -> fill os
(* Do not care about page that are not for us.. *)
in
(* Test wether the stream is theora *)
let test_theora () =
(* Get First page *)
let page = Ogg.Sync.read sync in
(* Check wether this is a b_o_s *)
if not (Ogg.Page.bos page) then raise Video.IO.Invalid_file;
(* Create a stream with this ID *)
let serial = Ogg.Page.serialno page in
Printf.printf "Testing stream %nx.\n" serial;
let os = Ogg.Stream.create ~serial () in
Ogg.Stream.put_page os page;
let packet = Ogg.Stream.get_packet os in
(* Test header. Do not catch anything, first page should be sufficient. *)
if not (Theora.Decoder.check packet) then raise Not_found;
Printf.printf "Got a theora stream!\n";
let dec = Theora.Decoder.create () in
(* Decode headers *)
let rec f packet =
try Theora.Decoder.headerin dec packet
with Ogg.Not_enough_data ->
let rec g () =
try
let packet = Ogg.Stream.get_packet os in
f packet
with Ogg.Not_enough_data ->
fill os;
g ()
in
g ()
in
let dec, info, _, _ = f packet in
(os, dec, info)
in
(* Now find a theora stream *)
let rec init () =
try test_theora () with
| Not_found ->
Printf.printf "This stream was not theora..\n";
init ()
| Video.IO.Invalid_file as e ->
Printf.printf "No theora stream was found..\n%!";
raise e
in
let os, dec, info = init () in
(* TODO: handle more formats *)
let _ = assert (info.Theora.pixel_fmt = Theora.PF_420) in
object (self)
method width = info.Theora.frame_width
method height = info.Theora.frame_height
method frame_rate =
float_of_int info.Theora.fps_numerator
/. float_of_int info.Theora.fps_denominator
val mutable latest_yuv = None
method private get_yuv =
try
let yuv = Theora.Decoder.get_yuv dec os in
let yuv =
Theora.(
Image.YUV420.make yuv.y_width yuv.y_height yuv.y yuv.y_stride yuv.u
yuv.Theora.v yuv.u_stride)
in
latest_yuv <- Some yuv;
yuv
with
| Ogg.Not_enough_data when not (Ogg.Stream.eos os) ->
fill os;
self#get_yuv
| Theora.Duplicate_frame -> (
(* Got a duplicate frame, sending previous one ! *)
match latest_yuv with
| Some x -> x
| None -> raise Video.IO.Invalid_file)
method read buf ofs len =
let n = ref 0 in
try
while !n < len do
buf.(ofs + !n) <- self#get_yuv;
incr n
done;
!n
with Ogg.Not_enough_data -> !n
method close = Unix.close fd
end