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
|
/* compile with
*
* gcc -o libharvid_example libharvid_example.c \
* -I../libharvid/ ../libharvid/libharvid.a \
* `pkg-config --cflags --libs libavcodec libavformat libswscale libavutil`
*
*/
#include <stdio.h>
#include <harvid.h>
/* ffmpeg decoder honors these externs */
int want_verbose = 0;
int want_quiet = 1;
/* dlog implementation required by libharvid */
#ifndef NDEBUG
int debug_section = 0;
#endif
int debug_level = 0;
void dlog(int level, const char *format, ...) {}
/* this example decodes frame #5 of the given video-file
* and write a ppm image to '/tmp/libharvid_example.ppm'
*/
void dothework(void *dc, void *vc, const char *file_name) {
unsigned short vid; // video id
void *cptr = NULL; // pointer to cacheline
uint8_t *bptr = NULL; // decoded video-frame data
VInfo ji; // video file info
int err = 0;
int decode_fmt = PIX_FMT_RGB24; // see libavutil.h
int64_t frame = 5; // video-frame to decode -- start counting at zero.
/* get (or create) numeric ID for given file */
vid = dctrl_get_id(vc, dc, file_name);
jvi_init(&ji);
/* get canonical output width/height and corresponding buffersize
* width,height == 0 -> original width, no-scaling
*/
if ((err=dctrl_get_info_scale(dc, vid, &ji,
/*out_width*/ 0 , /*out_height*/ 0, decode_fmt))
|| ji.buffersize < 1)
{
/* no decoder can be found, or the decoder can not provide information */
if (err == 503)
{
fprintf(stderr, "503/try again -- Service Temporarily Unavailable.\nNo decoder is available. The server is currently busy or overloaded.\n");
}
else
{
fprintf(stderr, "500/service unavailable -- No decoder is available\nFile is invalid (no video track, unknown codec, invalid geometry,..)\n");
}
return;
}
/* get frame from cache - or decode it into the cache
*
* Note: the 'cache' provides a zero-copy buffer to both
* the decoder-backend as well as to this user-code.
* -> it is not possible to bypass the cache.
*/
bptr = vcache_get_buffer(vc, dc, vid, frame, ji.out_width, ji.out_height, decode_fmt, &cptr, &err);
if (!bptr)
{
/* an error occured while decoding the frame */
if (err == 503)
{
fprintf(stderr, "503/try again -- Service Temporarily Unavailable\nVideo cache is unavailable. The server is currently busy or overloaded.\n");
}
else
{
fprintf(stderr, "500/service unavailable -- No decoder or cache is available\nFile is invalid (no video track, unknown codec, invalid geometry,..)\n");
}
return;
}
/* DO SOMETHING WITH THE VIDEO DATA */
const char * outfn = "/tmp/libharvid_example.ppm";
printf("writing ppm image to '%s' (%d bytes RGB, %dx%d)\n",
outfn, ji.buffersize, ji.out_width, ji.out_height);
FILE *x = fopen(outfn, "w");
fprintf(x, "P6\n%d %d\n255\n", ji.out_width, ji.out_height);
fwrite(bptr, ji.out_height, 3*ji.out_width, x);
fclose(x);
/* tell cache we're not using data at bptr (in cacheline cptr) anymore */
vcache_release_buffer(vc, cptr);
}
int main (int argc, char **argv) {
const int cache_size = 128;
const int max_decoder_threads = 8;
void *dc = NULL; // decoder control
void *vc = NULL; // video frame cache
/* initialize */
ff_initialize();
vcache_create(&vc);
vcache_resize(&vc, cache_size);
dctrl_create(&dc, max_decoder_threads, cache_size);
/* now multiple threads can access the decoder and cache
* simultaneously. There can be more user-threads than
* max_decoder_threads ..
*
* However, in this example we don't use pthreads..
*/
dothework(dc, vc, "/tmp/test.avi");
/* cleanup */
vcache_destroy(&vc);
dctrl_destroy(&dc);
ff_cleanup();
return 0;
}
|