1
1
//! Port from Original code: https://github.com/leandromoreira/ffmpeg-libav-tutorial/blob/master/0_hello_world.c
2
- //! Since this is a ported code, many warnings will emits.
3
- #![ allow( non_snake_case, non_camel_case_types, non_upper_case_globals) ]
4
2
use rusty_ffmpeg:: ffi;
5
3
6
4
use std:: {
7
5
ffi:: { CStr , CString } ,
8
6
fs:: File ,
9
7
io:: Write ,
10
- mem:: size_of,
11
- ptr:: null_mut,
12
- slice,
8
+ ptr, slice,
13
9
} ;
14
10
15
11
fn main ( ) {
16
12
let filepath: CString = CString :: new ( "./examples/slice/bear.mp4" ) . unwrap ( ) ;
17
13
18
14
println ! ( "initializing all the containers, codecs and protocols." ) ;
19
15
20
- let pFormatContext = unsafe { ffi:: avformat_alloc_context ( ) . as_mut ( ) }
21
- . expect ( "ERROR could not allocate memory for Format Context" ) ;
16
+ let mut format_context_ptr = unsafe { ffi:: avformat_alloc_context ( ) } ;
17
+ if format_context_ptr. is_null ( ) {
18
+ panic ! ( "ERROR could not allocate memory for Format Context" ) ;
19
+ }
22
20
23
21
println ! (
24
22
"opening the input file ({}) and loading format (container) header" ,
25
23
filepath. to_str( ) . unwrap( )
26
24
) ;
27
25
28
- let result = unsafe {
26
+ if unsafe {
29
27
ffi:: avformat_open_input (
30
- & mut ( pFormatContext as * mut _ ) ,
28
+ & mut format_context_ptr ,
31
29
filepath. as_ptr ( ) ,
32
- null_mut ( ) ,
33
- null_mut ( ) ,
30
+ ptr :: null_mut ( ) ,
31
+ ptr :: null_mut ( ) ,
34
32
)
35
- } ;
36
-
37
- if result != 0 {
33
+ } != 0
34
+ {
38
35
panic ! ( "ERROR could not open the file" ) ;
39
36
}
40
37
41
- let format_name = unsafe { CStr :: from_ptr ( ( * pFormatContext. iformat ) . name ) } ;
42
- let format_name = format_name. to_str ( ) . unwrap ( ) ;
38
+ let format_context = unsafe { format_context_ptr. as_mut ( ) } . unwrap ( ) ;
39
+
40
+ let format_name = unsafe { CStr :: from_ptr ( ( * format_context. iformat ) . name ) }
41
+ . to_str ( )
42
+ . unwrap ( ) ;
43
43
44
44
println ! (
45
45
"format {}, duration {} us, bit_rate {}" ,
46
- format_name, pFormatContext . duration, pFormatContext . bit_rate
46
+ format_name, format_context . duration, format_context . bit_rate
47
47
) ;
48
48
49
49
println ! ( "finding stream info from format" ) ;
50
50
51
- let result = unsafe { ffi:: avformat_find_stream_info ( pFormatContext, null_mut ( ) ) } ;
52
- if result < 0 {
51
+ if unsafe { ffi:: avformat_find_stream_info ( format_context, ptr:: null_mut ( ) ) } < 0 {
53
52
panic ! ( "ERROR could not get the stream info" ) ;
54
53
}
55
54
56
- let mut pCodec : * const ffi:: AVCodec = null_mut ( ) ;
57
- let mut pCodecParameters : * const ffi:: AVCodecParameters = null_mut ( ) ;
55
+ let mut codec_ptr : * const ffi:: AVCodec = ptr :: null_mut ( ) ;
56
+ let mut codec_parameters_ptr : * const ffi:: AVCodecParameters = ptr :: null_mut ( ) ;
58
57
let mut video_stream_index = None ;
59
58
60
- for i in 0 ..pFormatContext. nb_streams as i32 {
61
- let stream = unsafe {
62
- slice:: from_raw_parts ( pFormatContext. streams , size_of :: < ffi:: AVStream > ( ) ) [ i as usize ]
63
- . as_ref ( )
64
- }
65
- . unwrap ( ) ;
66
- let pLocalCodecParameters = unsafe { stream. codecpar . as_ref ( ) } . unwrap ( ) ;
59
+ let streams = unsafe {
60
+ slice:: from_raw_parts ( format_context. streams , format_context. nb_streams as usize )
61
+ } ;
62
+
63
+ for ( i, stream) in streams
64
+ . iter ( )
65
+ . map ( |stream| unsafe { stream. as_ref ( ) } . unwrap ( ) )
66
+ . enumerate ( )
67
+ {
67
68
println ! (
68
69
"AVStream->time_base before open coded {}/{}" ,
69
70
stream. time_base. num, stream. time_base. den
@@ -76,141 +77,139 @@ fn main() {
76
77
println ! ( "AVStream->duration {}" , stream. duration) ;
77
78
println ! ( "finding the proper decoder (CODEC)" ) ;
78
79
79
- let pLocalCodec =
80
- unsafe { ffi:: avcodec_find_decoder ( pLocalCodecParameters. codec_id ) . as_ref ( ) }
80
+ let local_codec_params = unsafe { stream. codecpar . as_ref ( ) } . unwrap ( ) ;
81
+ let local_codec =
82
+ unsafe { ffi:: avcodec_find_decoder ( local_codec_params. codec_id ) . as_ref ( ) }
81
83
. expect ( "ERROR unsupported codec!" ) ;
82
84
83
- if pLocalCodecParameters. codec_type == ffi:: AVMediaType_AVMEDIA_TYPE_VIDEO {
84
- if video_stream_index. is_none ( ) {
85
- video_stream_index = Some ( i) ;
86
- pCodec = pLocalCodec;
87
- pCodecParameters = pLocalCodecParameters;
85
+ match local_codec_params. codec_type {
86
+ ffi:: AVMediaType_AVMEDIA_TYPE_VIDEO => {
87
+ if video_stream_index. is_none ( ) {
88
+ video_stream_index = Some ( i) ;
89
+ codec_ptr = local_codec;
90
+ codec_parameters_ptr = local_codec_params;
91
+ }
92
+
93
+ println ! (
94
+ "Video Codec: resolution {} x {}" ,
95
+ local_codec_params. width, local_codec_params. height
96
+ ) ;
88
97
}
98
+ ffi:: AVMediaType_AVMEDIA_TYPE_AUDIO => {
99
+ println ! (
100
+ "Audio Codec: {} channels, sample rate {}" ,
101
+ local_codec_params. channels, local_codec_params. sample_rate
102
+ ) ;
103
+ }
104
+ _ => { }
105
+ } ;
89
106
90
- println ! (
91
- "Video Codec: resolution {} x {}" ,
92
- pLocalCodecParameters. width, pLocalCodecParameters. height
93
- ) ;
94
- } else if pLocalCodecParameters. codec_type == ffi:: AVMediaType_AVMEDIA_TYPE_AUDIO {
95
- println ! (
96
- "Audio Codec: {} channels, sample rate {}" ,
97
- pLocalCodecParameters. channels, pLocalCodecParameters. sample_rate
98
- ) ;
99
- }
100
-
101
- let codec_name = unsafe { CStr :: from_ptr ( pLocalCodec. name ) } ;
102
-
103
- let codec_name = codec_name. to_str ( ) . unwrap ( ) ;
107
+ let codec_name = unsafe { CStr :: from_ptr ( local_codec. name ) }
108
+ . to_str ( )
109
+ . unwrap ( ) ;
104
110
105
111
println ! (
106
112
"\t Codec {} ID {} bit_rate {}" ,
107
- codec_name, pLocalCodec . id, pLocalCodecParameters . bit_rate
113
+ codec_name, local_codec . id, local_codec_params . bit_rate
108
114
) ;
109
115
}
110
- let pCodecContext = unsafe { ffi:: avcodec_alloc_context3 ( pCodec ) . as_mut ( ) }
116
+ let codec_context = unsafe { ffi:: avcodec_alloc_context3 ( codec_ptr ) . as_mut ( ) }
111
117
. expect ( "failed to allocated memory for AVCodecContext" ) ;
112
118
113
- let result = unsafe { ffi:: avcodec_parameters_to_context ( pCodecContext, pCodecParameters) } ;
114
- if result < 0 {
119
+ if unsafe { ffi:: avcodec_parameters_to_context ( codec_context, codec_parameters_ptr) } < 0 {
115
120
panic ! ( "failed to copy codec params to codec context" ) ;
116
121
}
117
122
118
- let result = unsafe { ffi:: avcodec_open2 ( pCodecContext, pCodec, null_mut ( ) ) } ;
119
- if result < 0 {
123
+ if unsafe { ffi:: avcodec_open2 ( codec_context, codec_ptr, ptr:: null_mut ( ) ) } < 0 {
120
124
panic ! ( "failed to open codec through avcodec_open2" ) ;
121
125
}
122
126
123
- let pFrame =
127
+ let frame =
124
128
unsafe { ffi:: av_frame_alloc ( ) . as_mut ( ) } . expect ( "failed to allocated memory for AVFrame" ) ;
125
- let pPacket = unsafe { ffi:: av_packet_alloc ( ) . as_mut ( ) }
129
+ let packet = unsafe { ffi:: av_packet_alloc ( ) . as_mut ( ) }
126
130
. expect ( "failed to allocated memory for AVPacket" ) ;
127
131
128
- let mut how_many_packets_to_process = 8 ;
132
+ let mut packets_waiting = 8 ;
129
133
130
- while unsafe { ffi:: av_read_frame ( pFormatContext, pPacket) } >= 0 {
131
- if Some ( pPacket. stream_index ) == video_stream_index {
132
- println ! ( "AVPacket->pts {}" , pPacket. pts) ;
133
- if let Err ( s) = decode_packet ( pPacket, pCodecContext, pFrame) {
134
- panic ! ( s) ;
135
- }
136
- how_many_packets_to_process -= 1 ;
137
- if how_many_packets_to_process <= 0 {
134
+ while unsafe { ffi:: av_read_frame ( format_context, packet) } >= 0 {
135
+ if video_stream_index == Some ( packet. stream_index as usize ) {
136
+ println ! ( "AVPacket->pts {}" , packet. pts) ;
137
+ decode_packet ( packet, codec_context, frame) . unwrap ( ) ;
138
+ packets_waiting -= 1 ;
139
+ if packets_waiting <= 0 {
138
140
break ;
139
141
}
140
142
}
141
- unsafe { ffi:: av_packet_unref ( pPacket ) } ;
143
+ unsafe { ffi:: av_packet_unref ( packet ) } ;
142
144
}
143
145
144
146
println ! ( "releasing all the resources" ) ;
145
147
146
148
unsafe {
147
- ffi:: avformat_close_input ( & mut ( pFormatContext as * mut _ ) ) ;
148
- ffi:: av_packet_free ( & mut ( pPacket as * mut _ ) ) ;
149
- ffi:: av_frame_free ( & mut ( pFrame as * mut _ ) ) ;
150
- ffi:: avcodec_free_context ( & mut ( pCodecContext as * mut _ ) ) ;
149
+ ffi:: avformat_close_input ( & mut ( format_context as * mut _ ) ) ;
150
+ ffi:: av_packet_free ( & mut ( packet as * mut _ ) ) ;
151
+ ffi:: av_frame_free ( & mut ( frame as * mut _ ) ) ;
152
+ ffi:: avcodec_free_context ( & mut ( codec_context as * mut _ ) ) ;
151
153
}
152
154
}
153
155
154
156
fn decode_packet (
155
- pPacket : & ffi:: AVPacket ,
156
- pCodecContext : & mut ffi:: AVCodecContext ,
157
- pFrame : & mut ffi:: AVFrame ,
157
+ packet : & ffi:: AVPacket ,
158
+ codec_context : & mut ffi:: AVCodecContext ,
159
+ frame : & mut ffi:: AVFrame ,
158
160
) -> Result < ( ) , String > {
159
- let response = unsafe { ffi:: avcodec_send_packet ( pCodecContext , pPacket ) } ;
161
+ let mut response = unsafe { ffi:: avcodec_send_packet ( codec_context , packet ) } ;
160
162
161
163
if response < 0 {
162
164
return Err ( String :: from ( "Error while sending a packet to the decoder." ) ) ;
163
165
}
164
166
165
167
while response >= 0 {
166
- let response = unsafe { ffi:: avcodec_receive_frame ( pCodecContext , pFrame ) } ;
167
- if response == ffi:: AVERROR ( ffi:: EAGAIN as i32 ) || response == ffi:: AVERROR_EOF {
168
+ response = unsafe { ffi:: avcodec_receive_frame ( codec_context , frame ) } ;
169
+ if response == ffi:: AVERROR ( ffi:: EAGAIN ) || response == ffi:: AVERROR_EOF {
168
170
break ;
169
171
} else if response < 0 {
170
172
return Err ( String :: from (
171
173
"Error while receiving a frame from the decoder." ,
172
174
) ) ;
173
- }
174
-
175
- if response >= 0 {
175
+ } else {
176
176
println ! (
177
177
"Frame {} (type={}, size={} bytes) pts {} key_frame {} [DTS {}]" ,
178
- pCodecContext . frame_number,
179
- unsafe { ffi:: av_get_picture_type_char( pFrame . pict_type) } ,
180
- pFrame . pkt_size,
181
- pFrame . pts,
182
- pFrame . key_frame,
183
- pFrame . coded_picture_number
178
+ codec_context . frame_number,
179
+ unsafe { ffi:: av_get_picture_type_char( frame . pict_type) } ,
180
+ frame . pkt_size,
181
+ frame . pts,
182
+ frame . key_frame,
183
+ frame . coded_picture_number
184
184
) ;
185
185
186
186
let frame_filename = format ! (
187
187
"./examples/slice/output/frame-{}.pgm" ,
188
- pCodecContext . frame_number
188
+ codec_context . frame_number
189
189
) ;
190
- let width = pFrame . width as usize ;
191
- let height = pFrame . height as usize ;
192
- let wrap = pFrame . linesize [ 0 ] as usize ;
193
- let data = unsafe { slice:: from_raw_parts ( pFrame . data [ 0 ] , wrap * height) } ;
194
- save_gray_frame ( data, wrap, width, height, frame_filename) ;
190
+ let width = frame . width as usize ;
191
+ let height = frame . height as usize ;
192
+ let wrap = frame . linesize [ 0 ] as usize ;
193
+ let data = unsafe { slice:: from_raw_parts ( frame . data [ 0 ] , wrap * height) } ;
194
+ save_gray_frame ( data, wrap, width, height, frame_filename) . unwrap ( ) ;
195
195
}
196
196
}
197
197
Ok ( ( ) )
198
198
}
199
199
200
- fn save_gray_frame ( buf : & [ u8 ] , wrap : usize , xsize : usize , ysize : usize , filename : String ) -> bool {
201
- let mut file = match File :: create ( filename) {
202
- Ok ( file) => file,
203
- Err ( _) => return false ,
204
- } ;
200
+ fn save_gray_frame (
201
+ buf : & [ u8 ] ,
202
+ wrap : usize ,
203
+ xsize : usize ,
204
+ ysize : usize ,
205
+ filename : String ,
206
+ ) -> Result < ( ) , std:: io:: Error > {
207
+ let mut file = File :: create ( filename) ?;
205
208
let data = format ! ( "P5\n {} {}\n {}\n " , xsize, ysize, 255 ) ;
206
- if let Err ( _) = file. write_all ( data. as_bytes ( ) ) {
207
- return false ;
208
- }
209
+ file. write_all ( data. as_bytes ( ) ) ?;
209
210
210
211
for i in 0 ..ysize {
211
- if let Err ( _) = file. write_all ( & buf[ i * wrap..( i * wrap + xsize) ] ) {
212
- return false ;
213
- }
212
+ file. write_all ( & buf[ i * wrap..( i * wrap + xsize) ] ) ?;
214
213
}
215
- true
214
+ Ok ( ( ) )
216
215
}
0 commit comments