-
Notifications
You must be signed in to change notification settings - Fork 0
/
getframe.cpp
137 lines (93 loc) · 3.96 KB
/
getframe.cpp
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
///
// geared for libav 0.8.5
#include <cstdlib>
#include <iostream>
extern "C" {
#include <libavformat/avformat.h>
}
std::string filename = "bluescreen.avi";
AVFormatContext * av_input;
AVStream * vstream; // video stream
AVStream * astream; // audio stream
AVFrame * rgbframe; // AVFrame structure (video frame)
void die(std::string str) { std::cerr << str << std::endl; std::abort(); }
void init_stuff();
void cleanup_stuff();
void info_stuff();
int main() {
init_stuff();
info_stuff();
// TODO: two frame functions
//~ getRandomFrame(42); // stateless
//~ getNextFrame(); // stateful, more efficient: batch decoding, no keyframe seeking
// WARNING: lots of return code error checking omitted in following block
AVPacket packet;
//~ av_init_packet(&packet); # possibly optional
int rv = av_read_frame(av_input, &packet);
AVFrame * frame;
frame = avcodec_alloc_frame();
int got_frame;
rv = avcodec_decode_video2(vstream->codec, frame, &got_frame, &packet);
std::cout << "\nFirst frame info (http://ffmpeg.org/doxygen/trunk/structAVFrame.html)" << std::endl;
std::cout << " linesize: " << frame->linesize << std::endl;
std::cout << " sizeof(data): " << sizeof(frame->data) << std::endl;
std::cout << " dimensions: " << frame->width << "x" << frame->height << std::endl;
std::cout << " audio samples per channel: " << frame->nb_samples << std::endl;
std::cout << " first 10 pixels from data[0] vector (img data):" << std::endl << " ";
for(int i = 0; i < 10; ++i) std::cout << " " << (int)frame->data[0][i];
cleanup_stuff();
return EXIT_SUCCESS;
}
void init_stuff() {
av_register_all();
// open containers:
if(avformat_open_input(&av_input, filename.c_str(), NULL, NULL) != 0) die("open input error");
if(avformat_find_stream_info(av_input, NULL) < 0) die("stream info error");
for(int i=0; i < av_input->nb_streams; i++) {
if(av_input->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
vstream = av_input->streams[i];
break;
}
}
if(!vstream) die("no video stream!");
for(int i=0; i < av_input->nb_streams; i++) {
if(av_input->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
astream = av_input->streams[i];
break;
}
} // don't check if present because it might be audioless
// load codecs:
AVCodec *codec;
codec = avcodec_find_decoder(vstream->codec->codec_id);
if(!codec) die("no known codec!");
else std::cout << "codec is: " << codec->name << std::endl;
if(codec->capabilities & CODEC_CAP_TRUNCATED)
vstream->codec->flags |= CODEC_FLAG_TRUNCATED;
if(avcodec_open2(vstream->codec, codec, NULL) < 0) die("cannot open codec!");
// prepare frame:
rgbframe = avcodec_alloc_frame();
if(!rgbframe) die("unable to allocate rgbframe");
int size = avpicture_get_size(PIX_FMT_RGB24, vstream->codec->width, vstream->codec->height);
uint8_t * frame_buf = new uint8_t[size];
// TODO: use something "smart"-er than array pointer for buffer -> free at cleanup
if(!frame_buf) { av_free(rgbframe); die("error allocating frame_buf"); }
avpicture_fill((AVPicture *)rgbframe, frame_buf, PIX_FMT_RGB24, vstream->codec->width, vstream->codec->height);
}
void cleanup_stuff() {
if(rgbframe) {
av_free(rgbframe->data[0]);
av_free(rgbframe);
rgbframe = NULL;
}
if(vstream) if(vstream->codec->codec) avcodec_close(vstream->codec);
// TODO: close/free output and video out buffer
// TODO: close output files manually (no avformat_close_output)
if(av_input) avformat_close_input(&av_input);
else if(vstream) av_freep(&vstream);
}
void info_stuff() {
std::cout << std::endl;
av_dump_format(av_input, 0, filename.c_str(), false);
double framerate = (double)vstream->r_frame_rate.num / (double)vstream->r_frame_rate.den;
std::cout << "\tframerate (fps): " << framerate << std::endl;
}