WARNING: The online documentation has moved to https://docs.pjsip.org.

Visit the new documentation at https://docs.pjsip.org:

BLOG | DOCUMENTATION | GITHUB

Home --> Documentations --> PJMEDIA Reference

Samples: Video Codec Test

Video codec encode and decode test.

This file is pjsip-apps/src/samples/vid_codec_test.c

1/*
2 * Copyright (C) 2014 Teluu Inc. (http://www.teluu.com)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
30#include <pjlib.h>
31#include <pjlib-util.h>
32#include <pjmedia.h>
33#include <pjmedia-codec.h>
34
35
36#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
37
38
39#include <stdlib.h> /* atoi() */
40#include <stdio.h>
41
42#include "util.h"
43
44
45#define THIS_FILE "vid_vodec_test.c"
46
47
48/* If set, local renderer will be created to play original file */
49#define HAS_LOCAL_RENDERER_FOR_PLAY_FILE 1
50
51
52/* Default width and height for the renderer, better be set to maximum
53 * acceptable size.
54 */
55#define DEF_RENDERER_WIDTH 640
56#define DEF_RENDERER_HEIGHT 480
57
58
59/* Prototype for LIBSRTP utility in file datatypes.c */
60int hex_string_to_octet_string(char *raw, char *hex, int len);
61
62/*
63 * Register all codecs.
64 */
65static pj_status_t init_codecs(pj_pool_factory *pf)
66{
67 pj_status_t status;
68
69 /* To suppress warning about unused var when all codecs are disabled */
70 PJ_UNUSED_ARG(status);
71
72#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
73 status = pjmedia_codec_openh264_vid_init(NULL, pf);
74 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
75#endif
76
77#if defined(PJMEDIA_HAS_VID_TOOLBOX_CODEC) && \
78 PJMEDIA_HAS_VID_TOOLBOX_CODEC != 0
79 status = pjmedia_codec_vid_toolbox_init(NULL, pf);
80 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
81#endif
82
83#if defined(PJMEDIA_HAS_VPX_CODEC) && PJMEDIA_HAS_VPX_CODEC != 0
84 status = pjmedia_codec_vpx_vid_init(NULL, pf);
85 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
86#endif
87
88#if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
89 status = pjmedia_codec_ffmpeg_vid_init(NULL, pf);
90 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
91#endif
92
93 return PJ_SUCCESS;
94}
95
96/*
97 * Register all codecs.
98 */
99static void deinit_codecs()
100{
101#if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
103#endif
104
105#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
107#endif
108
109#if defined(PJMEDIA_HAS_VID_TOOLBOX_CODEC) && \
110 PJMEDIA_HAS_VID_TOOLBOX_CODEC != 0
112#endif
113
114#if defined(PJMEDIA_HAS_VPX_CODEC) && PJMEDIA_HAS_VPX_CODEC != 0
116#endif
117
118}
119
120
121static void show_diff(const pj_uint8_t *buf1, const pj_uint8_t *buf2,
122 unsigned size)
123{
124 enum {
125 STEP = 50
126 };
127 unsigned i=0;
128
129 for (; i<size; ) {
130 const pj_uint8_t *p1 = buf1 + i, *p2 = buf2 + i;
131 unsigned j;
132
133 printf("%8d ", i);
134 for (j=0; j<STEP && i+j<size; ++j) {
135 printf(" %02x", *(p1+j));
136 }
137 printf("\n");
138 printf(" ");
139 for (j=0; j<STEP && i+j<size; ++j) {
140 if (*(p1+j) == *(p2+j)) {
141 printf(" %02x", *(p2+j));
142 } else {
143 printf(" %02x", *(p2+j));
144 }
145 }
146 printf("\n");
147
148 i += j;
149 }
150}
151
152static void diff_file()
153{
154 const char *filename[2] = {
155 "/home/bennylp/Desktop/opt/src/openh264-svn/testbin/test.264",
156 "/home/bennylp/Desktop/opt/src/openh264-svn/testbin/test2.264"
157 };
158 unsigned size[2];
159 pj_uint8_t *buf[2], start_nal[3] = {0, 0, 1};
160 unsigned i, pos[2], frame_cnt, mismatch_cnt=0;
161
162 for (i=0; i<2; ++i) {
163 FILE *fhnd;
164 const pj_uint8_t start_nal[] = { 0, 0, 1};
165
166 fhnd = fopen(filename[i], "rb");
167 if (!fhnd) {
168 printf("Error opening %s\n", filename[i]);
169 return;
170 }
171
172 fseek(fhnd, 0, SEEK_END);
173 size[i] = ftell(fhnd);
174 fseek(fhnd, 0, SEEK_SET);
175
176 buf[i] = (pj_uint8_t*)malloc(size[i] + 4);
177 if (!buf[i]){
178 fclose(fhnd);
179 return;
180 }
181
182 if (fread (buf[i], 1, size[i], fhnd) != (unsigned)size[i]) {
183 fprintf (stderr, "Unable to read whole file\n");
184 fclose(fhnd);
185 return;
186 }
187
188 memcpy (buf[i] + size[i], start_nal, sizeof(start_nal));
189
190 fclose(fhnd);
191 }
192
193 if (size[0] != size[1]) {
194 printf("File size mismatch\n");
195 return;
196 }
197
198 pos[0] = pos[1] = 0;
199 for ( frame_cnt=0; ; ++frame_cnt) {
200 unsigned nal_len[2];
201 for (i = 0; i < size[0]; i++) {
202 if (memcmp(buf[0] + pos[0] + i, start_nal,
203 sizeof(start_nal)) == 0 && i > 0)
204 {
205 break;
206 }
207 }
208 nal_len[0] = i;
209 for (i = 0; i < size[1]; i++) {
210 if (memcmp(buf[1] + pos[1] + i, start_nal,
211 sizeof(start_nal)) == 0 && i > 0)
212 {
213 break;
214 }
215 }
216 nal_len[1] = i;
217
218 if (nal_len[0] != nal_len[1]) {
219 printf("Different size in frame %d (%d vs %d)\n",
220 frame_cnt, nal_len[0], nal_len[1]);
221 }
222
223 if (memcmp(buf[0]+pos[0], buf[1]+pos[1], nal_len[0]) != 0) {
224 printf("Mismatch in frame %d\n", frame_cnt);
225 show_diff(buf[0]+pos[0], buf[1]+pos[1], nal_len[0]);
226 puts("");
227 ++mismatch_cnt;
228 }
229
230 pos[0] += nal_len[0];
231 pos[1] += nal_len[1];
232
233 if (pos[0] >= size[0])
234 break;
235 }
236
237 free(buf[0]);
238 free(buf[1]);
239
240 if (!mismatch_cnt)
241 puts("Files the same!");
242 else
243 printf("%d mismatches\n", mismatch_cnt);
244}
245
246/*
247 * main()
248 */
249int main(int argc, char *argv[])
250{
252 pjmedia_endpt *med_endpt;
253 pj_pool_t *pool;
254 pj_status_t status;
255
256 /* Codec */
257 char *codec_id = (char*)"H264";
258 const pjmedia_vid_codec_info *codec_info;
259 pjmedia_vid_codec_param codec_param;
260 pjmedia_vid_codec *codec = NULL;
261
262 //const char *save_filename =
263 // "/home/bennylp/Desktop/opt/src/openh264-svn/testbin/test.264";
264 const char *save_filename = NULL;
265
266 /* File */
267 enum
268 {
269 WIDTH = 320,
270 HEIGHT = 192,
271 FPS = 12,
272 YUV_SIZE = WIDTH * HEIGHT * 3 >> 1,
273 YUV_BUF_SIZE = YUV_SIZE + WIDTH,
274 MAX_FRAMES = 32,
275 MTU = 1500
276 };
277 FILE *fyuv = NULL;
278 FILE *f264 = NULL;
279 typedef pj_uint8_t enc_buf_type[MTU];
280 pj_uint8_t yuv_frame[YUV_BUF_SIZE];
281 enc_buf_type enc_buf[MAX_FRAMES];
282 unsigned read_cnt = 0,
283 pkt_cnt = 0,
284 dec_cnt = 0,
285 enc_cnt;
286
287 if (0) {
288 diff_file();
289 return 1;
290 }
291
292 /* init PJLIB : */
293 status = pj_init();
294 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
295
296 /* Must create a pool factory before we can allocate any memory. */
298
299 /* Initialize media endpoint. */
300 status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
301 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
302
303 /* Create memory pool for application purpose */
304 pool = pj_pool_create( &cp.factory, /* pool factory */
305 "app", /* pool name. */
306 4000, /* init size */
307 4000, /* increment size */
308 NULL /* callback on error */
309 );
310
311 /* Init video format manager */
312 pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
313
314 /* Init video converter manager */
316
317 /* Init event manager */
318 pjmedia_event_mgr_create(pool, 0, NULL);
319
320 /* Init video codec manager */
322
323 /* Register all supported codecs */
324 status = init_codecs(&cp.factory);
325 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
326
327 /* Open YUV file */
328 fyuv = fopen("pjsip-apps/bin/CiscoVT2people_320x192_12fps.yuv", "rb");
329 if (!fyuv) {
330 puts("Unable to open ../CiscoVT2people_320x192_12fps.yuv");
331 status = -1;
332 goto on_exit;
333 }
334
335 /* Write 264 file if wanted */
336 if (save_filename) {
337 f264 = fopen(save_filename, "wb");
338 }
339
340 /* Find which codec to use. */
341 if (codec_id) {
342 unsigned count = 1;
343 pj_str_t str_codec_id = pj_str(codec_id);
344
346 &str_codec_id, &count,
347 &codec_info, NULL);
348 if (status != PJ_SUCCESS) {
349 printf("Error: unable to find codec %s\n", codec_id);
350 goto on_exit;
351 }
352 } else {
353 static pjmedia_vid_codec_info info[1];
354 unsigned count = PJ_ARRAY_SIZE(info);
355
356 /* Default to first codec */
357 pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL);
358 codec_info = &info[0];
359 }
360
361 /* Get codec default param for info */
362 status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
363 &codec_param);
364 pj_assert(status == PJ_SUCCESS);
365
366 /* Alloc encoder */
367 status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info, &codec);
368 if (status != PJ_SUCCESS) {
369 PJ_PERROR(3,(THIS_FILE, status, "Error allocating codec"));
370 goto on_exit;
371 }
372
375 codec_param.enc_mtu = MTU;
376 codec_param.enc_fmt.det.vid.size.w = WIDTH;
377 codec_param.enc_fmt.det.vid.size.h = HEIGHT;
378 codec_param.enc_fmt.det.vid.fps.num = FPS;
379 codec_param.enc_fmt.det.vid.avg_bps = WIDTH * HEIGHT * FPS;
380
381 status = pjmedia_vid_codec_init(codec, pool);
382 if (status != PJ_SUCCESS) {
383 PJ_PERROR(3,(THIS_FILE, status, "Error initializing codec"));
384 goto on_exit;
385 }
386
387 status = pjmedia_vid_codec_open(codec, &codec_param);
388 if (status != PJ_SUCCESS) {
389 PJ_PERROR(3,(THIS_FILE, status, "Error opening codec"));
390 goto on_exit;
391 }
392
393 while (fread(yuv_frame, 1, YUV_SIZE, fyuv) == YUV_SIZE) {
394 pjmedia_frame frm_yuv, frm_enc[MAX_FRAMES];
395 pj_bool_t has_more = PJ_FALSE;
396 const pj_uint8_t start_nal[] = { 0, 0, 1 };
397
398 ++ read_cnt;
399
400 pj_bzero(&frm_enc, sizeof(frm_enc));
401 pj_bzero(&frm_yuv, sizeof(frm_yuv));
402
403 frm_yuv.buf = yuv_frame;
404 frm_yuv.size = YUV_SIZE;
405
406 enc_cnt = 0;
407 frm_enc[enc_cnt].buf = enc_buf[enc_cnt];
408 frm_enc[enc_cnt].size = MTU;
409
410 status = pjmedia_vid_codec_encode_begin(codec, NULL, &frm_yuv,
411 MTU, &frm_enc[enc_cnt],
412 &has_more);
413 if (status != PJ_SUCCESS) {
414 PJ_PERROR(3,(THIS_FILE, status, "Codec encode error"));
415 goto on_exit;
416 }
417 if (frm_enc[enc_cnt].size) {
418 if (f264) {
419 fwrite(start_nal, 1, sizeof(start_nal), f264);
420 fwrite(frm_enc[enc_cnt].buf, 1, frm_enc[enc_cnt].size, f264);
421 }
422 ++pkt_cnt;
423 ++enc_cnt;
424 }
425
426 while (has_more) {
427
428 if (enc_cnt >= MAX_FRAMES) {
429 status = -1;
430 puts("Error: too many encoded frames");
431 goto on_exit;
432 }
433
434 has_more = PJ_FALSE;
435 frm_enc[enc_cnt].buf = enc_buf[enc_cnt];
436 frm_enc[enc_cnt].size = MTU;
437
439 &frm_enc[enc_cnt],
440 &has_more);
441 if (status != PJ_SUCCESS) {
442 PJ_PERROR(3,(THIS_FILE, status, "Codec encode error"));
443 goto on_exit;
444 }
445
446 if (frm_enc[enc_cnt].size) {
447 if (f264) {
448 fwrite(start_nal, 1, sizeof(start_nal), f264);
449 fwrite(frm_enc[enc_cnt].buf, 1, frm_enc[enc_cnt].size,
450 f264);
451 }
452 ++pkt_cnt;
453 ++enc_cnt;
454 }
455 }
456
457 if (enc_cnt) {
458 frm_yuv.buf = yuv_frame;
459 frm_yuv.size = YUV_BUF_SIZE;
460 status = pjmedia_vid_codec_decode(codec, enc_cnt,
461 frm_enc,
462 YUV_BUF_SIZE,
463 &frm_yuv);
464 if (status != PJ_SUCCESS) {
465 PJ_PERROR(3,(THIS_FILE, status, "Codec decode error"));
466 goto on_exit;
467 }
468
469 if (frm_yuv.size != 0) {
470 ++dec_cnt;
471 }
472 }
473 }
474
475 printf("Done.\n"
476 " Read YUV frames: %d\n"
477 " Encoded packets: %d\n"
478 " Decoded YUV frames: %d\n",
479 read_cnt, pkt_cnt, dec_cnt);
480
481 /* Start deinitialization: */
482on_exit:
483 if (codec) {
486 }
487
488 if (f264)
489 fclose(f264);
490
491 if (fyuv)
492 fclose(fyuv);
493
494 /* Deinit codecs */
495 deinit_codecs();
496
497 /* Destroy event manager */
499
500 /* Release application pool */
501 pj_pool_release( pool );
502
503 /* Destroy media endpoint. */
504 pjmedia_endpt_destroy( med_endpt );
505
506 /* Destroy pool factory */
508
509 /* Shutdown PJLIB */
510 pj_shutdown();
511
512 /* Avoid compile warning */
513 PJ_UNUSED_ARG(app_perror);
514
515 return (status == PJ_SUCCESS) ? 0 : 1;
516}
517
518
519#else
520
521int main(int argc, char *argv[])
522{
523 PJ_UNUSED_ARG(argc);
524 PJ_UNUSED_ARG(argv);
525 puts("Error: this sample requires video capability "
526 "(PJMEDIA_HAS_VIDEO == 1)");
527 return -1;
528}
529
530#endif /* PJMEDIA_HAS_VIDEO */
pj_status_t pjmedia_codec_openh264_vid_init(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf)
pj_status_t pjmedia_codec_openh264_vid_deinit(void)
pj_status_t pjmedia_codec_ffmpeg_vid_deinit(void)
pj_status_t pjmedia_codec_ffmpeg_vid_init(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf)
pj_status_t pjmedia_codec_vid_toolbox_init(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf)
pj_status_t pjmedia_codec_vid_toolbox_deinit(void)
pj_status_t pjmedia_codec_vpx_vid_init(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf)
pj_status_t pjmedia_codec_vpx_vid_deinit(void)
pj_status_t pjmedia_converter_mgr_create(pj_pool_t *pool, pjmedia_converter_mgr **mgr)
pj_status_t pjmedia_event_mgr_create(pj_pool_t *pool, unsigned options, pjmedia_event_mgr **mgr)
void pjmedia_event_mgr_destroy(pjmedia_event_mgr *mgr)
pj_status_t pjmedia_video_format_mgr_create(pj_pool_t *pool, unsigned max_fmt, unsigned options, pjmedia_video_format_mgr **p_mgr)
struct pjmedia_endpt pjmedia_endpt
Definition: pjmedia/types.h:186
@ PJMEDIA_DIR_ENCODING_DECODING
Definition: pjmedia/types.h:172
pj_status_t pjmedia_vid_codec_encode_begin(pjmedia_vid_codec *codec, const pjmedia_vid_encode_opt *opt, const pjmedia_frame *input, unsigned out_size, pjmedia_frame *output, pj_bool_t *has_more)
Definition: vid_codec.h:765
pj_status_t pjmedia_vid_codec_mgr_get_default_param(pjmedia_vid_codec_mgr *mgr, const pjmedia_vid_codec_info *info, pjmedia_vid_codec_param *param)
pj_status_t pjmedia_vid_codec_mgr_dealloc_codec(pjmedia_vid_codec_mgr *mgr, pjmedia_vid_codec *codec)
pj_status_t pjmedia_vid_codec_mgr_enum_codecs(pjmedia_vid_codec_mgr *mgr, unsigned *count, pjmedia_vid_codec_info info[], unsigned *prio)
pj_status_t pjmedia_vid_codec_open(pjmedia_vid_codec *codec, pjmedia_vid_codec_param *param)
Definition: vid_codec.h:686
pj_status_t pjmedia_vid_codec_mgr_alloc_codec(pjmedia_vid_codec_mgr *mgr, const pjmedia_vid_codec_info *info, pjmedia_vid_codec **p_codec)
pj_status_t pjmedia_vid_codec_encode_more(pjmedia_vid_codec *codec, unsigned out_size, pjmedia_frame *output, pj_bool_t *has_more)
Definition: vid_codec.h:793
pj_status_t pjmedia_vid_codec_decode(pjmedia_vid_codec *codec, pj_size_t pkt_count, pjmedia_frame packets[], unsigned out_size, pjmedia_frame *output)
Definition: vid_codec.h:825
pj_status_t pjmedia_vid_codec_mgr_find_codecs_by_id(pjmedia_vid_codec_mgr *mgr, const pj_str_t *codec_id, unsigned *count, const pjmedia_vid_codec_info *p_info[], unsigned prio[])
pj_status_t pjmedia_vid_codec_close(pjmedia_vid_codec *codec)
Definition: vid_codec.h:701
pj_status_t pjmedia_vid_codec_mgr_create(pj_pool_t *pool, pjmedia_vid_codec_mgr **mgr)
pj_status_t pjmedia_vid_codec_init(pjmedia_vid_codec *codec, pj_pool_t *pool)
Definition: vid_codec.h:667
@ PJMEDIA_VID_PACKING_PACKETS
Definition: vid_codec.h:65
pj_status_t pjmedia_endpt_create(pj_pool_factory *pf, pj_ioqueue_t *ioqueue, unsigned worker_cnt, pjmedia_endpt **p_endpt)
Definition: endpoint.h:127
pj_status_t pjmedia_endpt_destroy(pjmedia_endpt *endpt)
Definition: endpoint.h:168
unsigned char pj_uint8_t
pj_status_t pj_init(void)
int pj_bool_t
int pj_status_t
#define PJ_ARRAY_SIZE(a)
void pj_shutdown(void)
PJ_SUCCESS
PJ_FALSE
void pj_caching_pool_destroy(pj_caching_pool *ch_pool)
void pj_caching_pool_init(pj_caching_pool *ch_pool, const pj_pool_factory_policy *policy, pj_size_t max_capacity)
pj_pool_factory_policy pj_pool_factory_default_policy
pj_pool_t * pj_pool_create(pj_pool_factory *factory, const char *name, pj_size_t initial_size, pj_size_t increment_size, pj_pool_callback *callback)
void pj_pool_release(pj_pool_t *pool)
pj_str_t pj_str(char *str)
void pj_bzero(void *dst, pj_size_t size)
#define pj_assert(expr)
#define PJ_ASSERT_RETURN(expr, retval)
#define PJ_UNUSED_ARG(arg)
#define PJ_PERROR(level, arg)
Include all codecs API in PJMEDIA-CODEC.
PJMEDIA main header file.
Definition: siprtp.c:101
pj_pool_factory factory
union pjmedia_format::@11 det
pjmedia_video_format_detail vid
Definition: format.h:328
Definition: frame.h:56
void * buf
Definition: frame.h:58
pj_size_t size
Definition: frame.h:59
unsigned h
Definition: pjmedia/types.h:236
unsigned w
Definition: pjmedia/types.h:235
Definition: vid_codec.h:114
Definition: vid_codec.h:148
pjmedia_dir dir
Definition: vid_codec.h:149
pjmedia_vid_packing packing
Definition: vid_codec.h:150
pjmedia_format enc_fmt
Definition: vid_codec.h:152
unsigned enc_mtu
Definition: vid_codec.h:154
Definition: vid_codec.h:271
pjmedia_rect_size size
Definition: format.h:276
pjmedia_ratio fps
Definition: format.h:277
pj_uint32_t avg_bps
Definition: format.h:278

 


PJMEDIA small footprint Open Source media stack
Copyright (C) 2006-2008 Teluu Inc.