blob: 3bd9aaaacb3058fe6181cf5c5d62bf2d2b86e243 [file] [log] [blame]
Sauw Mingb1b17d22010-12-20 11:02:48 +00001/* $Id$ */
2/*
3 * Copyright (C) 2010-2011 Teluu Inc. (http://www.teluu.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include <pjmedia.h>
21#include <pjmedia/converter.h>
22#include <pjmedia-codec.h>
23#include <pjlib-util.h>
24#include <pjlib.h>
25#include <stdio.h>
26#include <stdlib.h>
27
28#include "util.h"
29
30/**
31 * \page page_pjmedia_samples_aviplay_c Samples: Playing AVI File to
32 * Video and Sound Devices
33 *
34 * This is a very simple example to use the @ref PJMEDIA_FILE_PLAY,
35 * @ref PJMED_SND_PORT, and @ref PJMEDIA_VID_PORT. In this example, we
36 * open the file, video, and sound devices, then connect the file to both
37 * video and sound devices to play the contents of the file.
38 *
39 *
40 * This file is pjsip-apps/src/samples/aviplay.c
41 *
42 * \includelineno aviplay.c
43 */
44
45
46/*
47 * aviplay.c
48 *
49 * PURPOSE:
50 * Play a AVI file to video and sound devices.
51 *
52 * USAGE:
53 * aviplay FILE.AVI
54 */
55
56
57/* For logging purpose. */
58#define THIS_FILE "aviplay.c"
59
Sauw Mingb1b17d22010-12-20 11:02:48 +000060static const char *desc =
61" FILE \n"
62" \n"
63" aviplay.c \n"
64" \n"
65" PURPOSE \n"
66" \n"
67" Demonstrate how to play a AVI file. \n"
68" \n"
69" USAGE \n"
70" \n"
71" aviplay FILE.AVI \n";
72
73struct codec_fmt {
74 pj_uint32_t pjmedia_id;
75 const char *codec_id;
76 /* Do we need to convert the decoded frame? */
77 pj_bool_t need_conversion;
78 /* If conversion is needed, dst_fmt indicates the destination format */
79 pjmedia_format_id dst_fmt;
80} codec_fmts[] = {{PJMEDIA_FORMAT_MJPEG, "mjpeg",
81 PJ_TRUE , PJMEDIA_FORMAT_I420},
82 {PJMEDIA_FORMAT_H263 , "h263" ,
83 PJ_FALSE, 0},
Nanang Izzuddin235e1b42011-02-28 18:59:47 +000084 {PJMEDIA_FORMAT_XVID , "xvid"},
Sauw Mingb1b17d22010-12-20 11:02:48 +000085 };
86
87typedef struct avi_port_t
88{
89 pjmedia_vid_port *vid_port;
Sauw Ming8e799122010-12-30 16:31:16 +000090 pjmedia_snd_port *snd_port;
Sauw Mingb1b17d22010-12-20 11:02:48 +000091 pj_bool_t is_running;
92 pj_bool_t is_quitting;
93} avi_port_t;
94
95typedef struct codec_port_data_t
96{
97 pjmedia_vid_codec *codec;
98 pjmedia_port *src_port;
99 pj_uint8_t *enc_buf;
100 pj_size_t enc_buf_size;
101
102 pjmedia_converter *conv;
103} codec_port_data_t;
104
Benny Prijono934af0f2011-07-12 03:05:35 +0000105static pj_status_t avi_event_cb(pjmedia_event_subscription *esub,
106 pjmedia_event *event)
Sauw Mingb1b17d22010-12-20 11:02:48 +0000107{
Benny Prijono934af0f2011-07-12 03:05:35 +0000108 avi_port_t *ap = (avi_port_t *)esub->user_data;
Sauw Mingb1b17d22010-12-20 11:02:48 +0000109
Benny Prijono934af0f2011-07-12 03:05:35 +0000110 switch (event->type) {
111 case PJMEDIA_EVENT_WND_CLOSED:
Sauw Mingb1b17d22010-12-20 11:02:48 +0000112 ap->is_quitting = PJ_TRUE;
113 break;
Benny Prijono934af0f2011-07-12 03:05:35 +0000114 case PJMEDIA_EVENT_MOUSE_BTN_DOWN:
Sauw Mingb1b17d22010-12-20 11:02:48 +0000115 if (ap->is_running) {
116 pjmedia_vid_port_stop(ap->vid_port);
Sauw Ming8e799122010-12-30 16:31:16 +0000117 if (ap->snd_port)
118 pjmedia_aud_stream_stop(
119 pjmedia_snd_port_get_snd_stream(ap->snd_port));
Sauw Mingb1b17d22010-12-20 11:02:48 +0000120 } else {
121 pjmedia_vid_port_start(ap->vid_port);
Sauw Ming8e799122010-12-30 16:31:16 +0000122 if (ap->snd_port)
123 pjmedia_aud_stream_start(
124 pjmedia_snd_port_get_snd_stream(ap->snd_port));
Sauw Mingb1b17d22010-12-20 11:02:48 +0000125 }
126 ap->is_running = !ap->is_running;
127 break;
128 default:
129 return PJ_SUCCESS;
130 }
131
132 /* We handled the event on our own, so return non-PJ_SUCCESS here */
133 return -1;
134}
135
136static pj_status_t codec_get_frame(pjmedia_port *port,
137 pjmedia_frame *frame)
138{
139 codec_port_data_t *port_data = (codec_port_data_t*)port->port_data.pdata;
140 pjmedia_vid_codec *codec = port_data->codec;
141 pjmedia_frame enc_frame;
142 pj_status_t status;
143
144 enc_frame.buf = port_data->enc_buf;
145 enc_frame.size = port_data->enc_buf_size;
146
147 if (port_data->conv) {
148 pj_size_t frame_size = frame->size;
149
150 status = pjmedia_port_get_frame(port_data->src_port, frame);
151 if (status != PJ_SUCCESS) goto on_error;
152
153 status = codec->op->decode(codec, frame, frame->size, &enc_frame);
154 if (status != PJ_SUCCESS) goto on_error;
155
156 frame->size = frame_size;
157 status = pjmedia_converter_convert(port_data->conv, &enc_frame, frame);
158 if (status != PJ_SUCCESS) goto on_error;
159
160 return PJ_SUCCESS;
161 }
162
163 status = pjmedia_port_get_frame(port_data->src_port, &enc_frame);
164 if (status != PJ_SUCCESS) goto on_error;
165
166 status = codec->op->decode(codec, &enc_frame, frame->size, frame);
167 if (status != PJ_SUCCESS) goto on_error;
168
169 return PJ_SUCCESS;
170
171on_error:
172 pj_perror(3, THIS_FILE, status, "codec_get_frame() error");
173 return status;
174}
175
176static int aviplay(pj_pool_t *pool, const char *fname)
177{
178 pjmedia_vid_port *renderer=NULL;
179 pjmedia_vid_port_param param;
Sauw Mingb1b17d22010-12-20 11:02:48 +0000180 const pjmedia_video_format_info *vfi;
181 pjmedia_video_format_detail *vfd;
Sauw Ming8e799122010-12-30 16:31:16 +0000182 pjmedia_snd_port *snd_port = NULL;
Sauw Mingb1b17d22010-12-20 11:02:48 +0000183 pj_status_t status;
184 int rc = 0;
185 pjmedia_avi_streams *avi_streams;
186 pjmedia_avi_stream *vid_stream, *aud_stream;
187 pjmedia_port *vid_port = NULL, *aud_port = NULL;
188 pjmedia_vid_codec *codec=NULL;
Benny Prijono934af0f2011-07-12 03:05:35 +0000189 pjmedia_event_subscription esub;
Sauw Mingb1b17d22010-12-20 11:02:48 +0000190 avi_port_t avi_port;
191
192 pj_bzero(&avi_port, sizeof(avi_port));
193
194 status = pjmedia_avi_player_create_streams(pool, fname, 0, &avi_streams);
195 if (status != PJ_SUCCESS) {
196 PJ_PERROR(2,("", status, " Error playing %s", fname));
197 rc = 210; goto on_return;
198 }
199
200 vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
201 0,
202 PJMEDIA_TYPE_VIDEO);
203 vid_port = pjmedia_avi_stream_get_port(vid_stream);
204
205 if (vid_port) {
206 pjmedia_vid_port_param_default(&param);
207
208 status = pjmedia_vid_dev_default_param(pool,
209 PJMEDIA_VID_DEFAULT_RENDER_DEV,
210 &param.vidparam);
211 if (status != PJ_SUCCESS) {
212 rc = 220; goto on_return;
213 }
214
215 /* Create renderer, set it to active */
216 param.active = PJ_TRUE;
217 param.vidparam.dir = PJMEDIA_DIR_RENDER;
218 vfd = pjmedia_format_get_video_format_detail(&vid_port->info.fmt,
219 PJ_TRUE);
220 pjmedia_format_init_video(&param.vidparam.fmt,
221 vid_port->info.fmt.id,
222 vfd->size.w, vfd->size.h,
223 vfd->fps.num, vfd->fps.denum);
224
225 vfi = pjmedia_get_video_format_info(
226 pjmedia_video_format_mgr_instance(),
227 vid_port->info.fmt.id);
228 /* Check whether the frame is encoded */
229 if (!vfi || vfi->bpp == 0) {
230 /* Yes, prepare codec */
231 pj_str_t codec_id_st;
232 unsigned info_cnt = 1, i, k;
233 const pjmedia_vid_codec_info *codec_info;
234 pj_str_t port_name = {"codec", 5};
235 pj_uint8_t *enc_buf = NULL;
236 pj_size_t enc_buf_size = 0;
237 pjmedia_vid_dev_info rdr_info;
238 pjmedia_port codec_port;
239 codec_port_data_t codec_port_data;
240 pjmedia_vid_codec_param codec_param;
241 struct codec_fmt *codecp = NULL;
242
243 /* Lookup codec */
244 for (i = 0; i < sizeof(codec_fmts)/sizeof(codec_fmts[0]); i++) {
245 if (vid_port->info.fmt.id == codec_fmts[i].pjmedia_id) {
246 codecp = &codec_fmts[i];
247 break;
248 }
249 }
250 if (!codecp) {
251 rc = 242; goto on_return;
252 }
253 pj_cstr(&codec_id_st, codecp->codec_id);
254 status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
255 &codec_id_st,
256 &info_cnt,
257 &codec_info,
258 NULL);
259 if (status != PJ_SUCCESS) {
260 rc = 245; goto on_return;
261 }
262 status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
263 &codec_param);
264 if (status != PJ_SUCCESS) {
265 rc = 246; goto on_return;
266 }
267
268 pjmedia_vid_dev_get_info(param.vidparam.rend_id, &rdr_info);
269 for (i=0; i<codec_info->dec_fmt_id_cnt; ++i) {
270 for (k=0; k<rdr_info.fmt_cnt; ++k) {
271 if (codec_info->dec_fmt_id[i]==(int)rdr_info.fmt[k].id)
272 {
273 param.vidparam.fmt.id = codec_info->dec_fmt_id[i];
274 }
275 }
276 }
277
278 /* Open codec */
279 status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
280 &codec);
281 if (status != PJ_SUCCESS) {
282 rc = 250; goto on_return;
283 }
284
285 status = codec->op->init(codec, pool);
286 if (status != PJ_SUCCESS) {
287 rc = 251; goto on_return;
288 }
289
290 pjmedia_format_copy(&codec_param.dec_fmt, &param.vidparam.fmt);
291
292 status = codec->op->open(codec, &codec_param);
293 if (status != PJ_SUCCESS) {
294 rc = 252; goto on_return;
295 }
296
297 /* Alloc encoding buffer */
298 enc_buf_size = codec_param.dec_fmt.det.vid.size.w *
299 codec_param.dec_fmt.det.vid.size.h * 4
300 + 16; /*< padding, just in case */
301 enc_buf = pj_pool_alloc(pool,enc_buf_size);
302
303 /* Init codec port */
304 pj_bzero(&codec_port, sizeof(codec_port));
305 status = pjmedia_port_info_init2(&codec_port.info, &port_name,
306 0x1234,
307 PJMEDIA_DIR_ENCODING,
308 &codec_param.dec_fmt);
309 if (status != PJ_SUCCESS) {
310 rc = 260; goto on_return;
311 }
312 pj_bzero(&codec_port_data, sizeof(codec_port_data));
313 codec_port_data.codec = codec;
314 codec_port_data.src_port = vid_port;
315 codec_port_data.enc_buf = enc_buf;
316 codec_port_data.enc_buf_size = enc_buf_size;
317
318 codec_port.get_frame = &codec_get_frame;
319 codec_port.port_data.pdata = &codec_port_data;
320
321 /* Check whether we need to convert the decoded frame */
322 if (codecp->need_conversion) {
323 pjmedia_conversion_param conv_param;
324
Sauw Mingb1b17d22010-12-20 11:02:48 +0000325 pjmedia_format_copy(&conv_param.src, &param.vidparam.fmt);
326 pjmedia_format_copy(&conv_param.dst, &param.vidparam.fmt);
327 conv_param.dst.id = codecp->dst_fmt;
328 param.vidparam.fmt.id = conv_param.dst.id;
329
330 status = pjmedia_converter_create(NULL, pool, &conv_param,
331 &codec_port_data.conv);
332 if (status != PJ_SUCCESS) {
333 rc = 270; goto on_return;
334 }
335 }
336
337 status = pjmedia_vid_port_create(pool, &param, &renderer);
338 if (status != PJ_SUCCESS) {
339 rc = 230; goto on_return;
340 }
341
342 status = pjmedia_vid_port_connect(renderer, &codec_port,
343 PJ_FALSE);
344 } else {
345 status = pjmedia_vid_port_create(pool, &param, &renderer);
346 if (status != PJ_SUCCESS) {
347 rc = 230; goto on_return;
348 }
349
350 /* Connect avi port to renderer */
351 status = pjmedia_vid_port_connect(renderer, vid_port,
352 PJ_FALSE);
353 }
354
355 if (status != PJ_SUCCESS) {
356 rc = 240; goto on_return;
357 }
358 }
359
360 aud_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
361 0,
362 PJMEDIA_TYPE_AUDIO);
363 aud_port = pjmedia_avi_stream_get_port(aud_stream);
364
365 if (aud_port) {
Sauw Ming8e799122010-12-30 16:31:16 +0000366 /* Create sound player port. */
367 status = pjmedia_snd_port_create_player(
368 pool, /* pool */
369 -1, /* use default dev. */
370 PJMEDIA_PIA_SRATE(&aud_port->info),/* clock rate. */
371 PJMEDIA_PIA_CCNT(&aud_port->info), /* # of channels. */
372 PJMEDIA_PIA_SPF(&aud_port->info), /* samples per frame. */
373 PJMEDIA_PIA_BITS(&aud_port->info), /* bits per sample. */
374 0, /* options */
375 &snd_port /* returned port */
376 );
Sauw Mingb1b17d22010-12-20 11:02:48 +0000377 if (status != PJ_SUCCESS) {
378 rc = 310; goto on_return;
379 }
380
Sauw Ming8e799122010-12-30 16:31:16 +0000381 /* Connect file port to the sound player.
382 * Stream playing will commence immediately.
383 */
384 status = pjmedia_snd_port_connect(snd_port, aud_port);
Sauw Mingb1b17d22010-12-20 11:02:48 +0000385 if (status != PJ_SUCCESS) {
386 rc = 330; goto on_return;
387 }
388 }
389
390 if (vid_port) {
391 pjmedia_vid_cb cb;
392
393 pj_bzero(&cb, sizeof(cb));
Sauw Ming8e799122010-12-30 16:31:16 +0000394 avi_port.snd_port = snd_port;
Sauw Mingb1b17d22010-12-20 11:02:48 +0000395 avi_port.vid_port = renderer;
396 avi_port.is_running = PJ_TRUE;
397 pjmedia_vid_port_set_cb(renderer, &cb, &avi_port);
Sauw Ming8e799122010-12-30 16:31:16 +0000398
Benny Prijono934af0f2011-07-12 03:05:35 +0000399 /* subscribe events */
400 pjmedia_event_subscription_init(&esub, &avi_event_cb, &avi_port);
401 pjmedia_event_subscribe(
402 pjmedia_vid_port_get_event_publisher(renderer),
403 &esub);
404
Sauw Ming8e799122010-12-30 16:31:16 +0000405 if (snd_port) {
406 /* Synchronize video rendering and audio playback */
407 pjmedia_vid_port_set_clock_src(
Sauw Ming8985f552011-07-13 02:37:14 +0000408 renderer,
Sauw Ming8e799122010-12-30 16:31:16 +0000409 pjmedia_snd_port_get_clock_src(
410 snd_port, PJMEDIA_DIR_PLAYBACK));
411 }
412
Sauw Mingb1b17d22010-12-20 11:02:48 +0000413
414 /* Start video streaming.. */
415 status = pjmedia_vid_port_start(renderer);
416 if (status != PJ_SUCCESS) {
417 rc = 270; goto on_return;
418 }
419 }
420
421 while (!avi_port.is_quitting) {
422 pj_thread_sleep(100);
423 }
424
425on_return:
Sauw Ming8e799122010-12-30 16:31:16 +0000426 if (snd_port) {
427 pjmedia_snd_port_disconnect(snd_port);
428 /* Without this sleep, Windows/DirectSound will repeteadly
429 * play the last frame during destroy.
430 */
431 pj_thread_sleep(100);
432 pjmedia_snd_port_destroy(snd_port);
Sauw Mingb1b17d22010-12-20 11:02:48 +0000433 }
434 if (renderer)
435 pjmedia_vid_port_destroy(renderer);
Sauw Ming8e799122010-12-30 16:31:16 +0000436 if (aud_port)
437 pjmedia_port_destroy(aud_port);
Sauw Mingb1b17d22010-12-20 11:02:48 +0000438 if (vid_port)
439 pjmedia_port_destroy(vid_port);
440 if (codec) {
441 codec->op->close(codec);
442 pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
443 }
444
445 return rc;
446}
447
448
Sauw Ming01095d82011-07-14 08:46:19 +0000449static int main_func(int argc, char *argv[])
Sauw Mingb1b17d22010-12-20 11:02:48 +0000450{
451 pj_caching_pool cp;
452 pj_pool_t *pool;
453 int rc = 0;
454 pj_status_t status = PJ_SUCCESS;
455
456 if (argc != 2) {
457 puts("Error: filename required");
458 puts(desc);
459 return 1;
460 }
461
462
463 /* Must init PJLIB first: */
464 status = pj_init();
465 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
466
467 /* Must create a pool factory before we can allocate any memory. */
468 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
469
470 /* Create memory pool for our file player */
471 pool = pj_pool_create( &cp.factory, /* pool factory */
472 "AVI", /* pool name. */
473 4000, /* init size */
474 4000, /* increment size */
475 NULL /* callback on error */
476 );
477
478 pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
479 pjmedia_converter_mgr_create(pool, NULL);
480 pjmedia_vid_codec_mgr_create(pool, NULL);
481
Sauw Minge90ece82011-06-09 04:05:44 +0000482 status = pjmedia_vid_dev_subsys_init(&cp.factory);
Sauw Mingb1b17d22010-12-20 11:02:48 +0000483 if (status != PJ_SUCCESS)
484 goto on_return;
485
486 status = pjmedia_aud_subsys_init(&cp.factory);
487 if (status != PJ_SUCCESS) {
488 goto on_return;
489 }
490
491 status = pjmedia_codec_ffmpeg_init(NULL, &cp.factory);
492 if (status != PJ_SUCCESS)
493 goto on_return;
494
495 rc = aviplay(pool, argv[1]);
496
497 /*
498 * File should be playing and looping now
499 */
500
501 /* Without this sleep, Windows/DirectSound will repeteadly
502 * play the last frame during destroy.
503 */
504 pj_thread_sleep(100);
505
506on_return:
507 pjmedia_codec_ffmpeg_deinit();
508 pjmedia_aud_subsys_shutdown();
Sauw Minge90ece82011-06-09 04:05:44 +0000509 pjmedia_vid_dev_subsys_shutdown();
Sauw Mingb1b17d22010-12-20 11:02:48 +0000510
511 pjmedia_video_format_mgr_destroy(pjmedia_video_format_mgr_instance());
512 pjmedia_converter_mgr_destroy(pjmedia_converter_mgr_instance());
513 pjmedia_vid_codec_mgr_destroy(pjmedia_vid_codec_mgr_instance());
514
515 /* Release application pool */
516 pj_pool_release( pool );
517
518 /* Destroy pool factory */
519 pj_caching_pool_destroy( &cp );
520
521 /* Shutdown PJLIB */
522 pj_shutdown();
523
524 /* Done. */
525 return 0;
526}
Sauw Ming01095d82011-07-14 08:46:19 +0000527
528int main(int argc, char *argv[])
529{
530 return pj_run_app(&main_func, argc, argv, 0);
531}