blob: 2f12822d30dd1363ee653192d84597429c754add [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>
Sauw Ming1b39a642011-03-24 15:08:54 +000023#include <pjmedia_videodev.h>
Sauw Mingb1b17d22010-12-20 11:02:48 +000024#include <pjlib-util.h>
25#include <pjlib.h>
26#include <stdio.h>
27#include <stdlib.h>
28
29#include "util.h"
30
31/**
32 * \page page_pjmedia_samples_aviplay_c Samples: Playing AVI File to
33 * Video and Sound Devices
34 *
35 * This is a very simple example to use the @ref PJMEDIA_FILE_PLAY,
36 * @ref PJMED_SND_PORT, and @ref PJMEDIA_VID_PORT. In this example, we
37 * open the file, video, and sound devices, then connect the file to both
38 * video and sound devices to play the contents of the file.
39 *
40 *
41 * This file is pjsip-apps/src/samples/aviplay.c
42 *
43 * \includelineno aviplay.c
44 */
45
46
47/*
48 * aviplay.c
49 *
50 * PURPOSE:
51 * Play a AVI file to video and sound devices.
52 *
53 * USAGE:
54 * aviplay FILE.AVI
55 */
56
57
58/* For logging purpose. */
59#define THIS_FILE "aviplay.c"
60
Sauw Mingb1b17d22010-12-20 11:02:48 +000061static const char *desc =
62" FILE \n"
63" \n"
64" aviplay.c \n"
65" \n"
66" PURPOSE \n"
67" \n"
68" Demonstrate how to play a AVI file. \n"
69" \n"
70" USAGE \n"
71" \n"
72" aviplay FILE.AVI \n";
73
74struct codec_fmt {
75 pj_uint32_t pjmedia_id;
76 const char *codec_id;
77 /* Do we need to convert the decoded frame? */
78 pj_bool_t need_conversion;
79 /* If conversion is needed, dst_fmt indicates the destination format */
80 pjmedia_format_id dst_fmt;
81} codec_fmts[] = {{PJMEDIA_FORMAT_MJPEG, "mjpeg",
82 PJ_TRUE , PJMEDIA_FORMAT_I420},
83 {PJMEDIA_FORMAT_H263 , "h263" ,
84 PJ_FALSE, 0},
Nanang Izzuddin235e1b42011-02-28 18:59:47 +000085 {PJMEDIA_FORMAT_XVID , "xvid"},
Sauw Mingb1b17d22010-12-20 11:02:48 +000086 };
87
88typedef struct avi_port_t
89{
90 pjmedia_vid_port *vid_port;
Sauw Ming8e799122010-12-30 16:31:16 +000091 pjmedia_snd_port *snd_port;
Sauw Mingb1b17d22010-12-20 11:02:48 +000092 pj_bool_t is_running;
93 pj_bool_t is_quitting;
94} avi_port_t;
95
96typedef struct codec_port_data_t
97{
98 pjmedia_vid_codec *codec;
99 pjmedia_port *src_port;
100 pj_uint8_t *enc_buf;
101 pj_size_t enc_buf_size;
102
103 pjmedia_converter *conv;
104} codec_port_data_t;
105
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000106static pj_status_t avi_event_cb(pjmedia_vid_dev_stream *stream,
Sauw Mingb1b17d22010-12-20 11:02:48 +0000107 void *user_data,
108 pjmedia_vid_event *event)
109{
110 avi_port_t *ap = (avi_port_t *)user_data;
111
112 PJ_UNUSED_ARG(stream);
113
114 switch (event->event_type) {
115 case PJMEDIA_EVENT_WINDOW_CLOSE:
116 ap->is_quitting = PJ_TRUE;
117 break;
118 case PJMEDIA_EVENT_MOUSEBUTTONDOWN:
119 if (ap->is_running) {
120 pjmedia_vid_port_stop(ap->vid_port);
Sauw Ming8e799122010-12-30 16:31:16 +0000121 if (ap->snd_port)
122 pjmedia_aud_stream_stop(
123 pjmedia_snd_port_get_snd_stream(ap->snd_port));
Sauw Mingb1b17d22010-12-20 11:02:48 +0000124 } else {
125 pjmedia_vid_port_start(ap->vid_port);
Sauw Ming8e799122010-12-30 16:31:16 +0000126 if (ap->snd_port)
127 pjmedia_aud_stream_start(
128 pjmedia_snd_port_get_snd_stream(ap->snd_port));
Sauw Mingb1b17d22010-12-20 11:02:48 +0000129 }
130 ap->is_running = !ap->is_running;
131 break;
132 default:
133 return PJ_SUCCESS;
134 }
135
136 /* We handled the event on our own, so return non-PJ_SUCCESS here */
137 return -1;
138}
139
140static pj_status_t codec_get_frame(pjmedia_port *port,
141 pjmedia_frame *frame)
142{
143 codec_port_data_t *port_data = (codec_port_data_t*)port->port_data.pdata;
144 pjmedia_vid_codec *codec = port_data->codec;
145 pjmedia_frame enc_frame;
146 pj_status_t status;
147
148 enc_frame.buf = port_data->enc_buf;
149 enc_frame.size = port_data->enc_buf_size;
150
151 if (port_data->conv) {
152 pj_size_t frame_size = frame->size;
153
154 status = pjmedia_port_get_frame(port_data->src_port, frame);
155 if (status != PJ_SUCCESS) goto on_error;
156
157 status = codec->op->decode(codec, frame, frame->size, &enc_frame);
158 if (status != PJ_SUCCESS) goto on_error;
159
160 frame->size = frame_size;
161 status = pjmedia_converter_convert(port_data->conv, &enc_frame, frame);
162 if (status != PJ_SUCCESS) goto on_error;
163
164 return PJ_SUCCESS;
165 }
166
167 status = pjmedia_port_get_frame(port_data->src_port, &enc_frame);
168 if (status != PJ_SUCCESS) goto on_error;
169
170 status = codec->op->decode(codec, &enc_frame, frame->size, frame);
171 if (status != PJ_SUCCESS) goto on_error;
172
173 return PJ_SUCCESS;
174
175on_error:
176 pj_perror(3, THIS_FILE, status, "codec_get_frame() error");
177 return status;
178}
179
180static int aviplay(pj_pool_t *pool, const char *fname)
181{
182 pjmedia_vid_port *renderer=NULL;
183 pjmedia_vid_port_param param;
Sauw Mingb1b17d22010-12-20 11:02:48 +0000184 const pjmedia_video_format_info *vfi;
185 pjmedia_video_format_detail *vfd;
Sauw Ming8e799122010-12-30 16:31:16 +0000186 pjmedia_snd_port *snd_port = NULL;
Sauw Mingb1b17d22010-12-20 11:02:48 +0000187 pj_status_t status;
188 int rc = 0;
189 pjmedia_avi_streams *avi_streams;
190 pjmedia_avi_stream *vid_stream, *aud_stream;
191 pjmedia_port *vid_port = NULL, *aud_port = NULL;
192 pjmedia_vid_codec *codec=NULL;
193 avi_port_t avi_port;
194
195 pj_bzero(&avi_port, sizeof(avi_port));
196
197 status = pjmedia_avi_player_create_streams(pool, fname, 0, &avi_streams);
198 if (status != PJ_SUCCESS) {
199 PJ_PERROR(2,("", status, " Error playing %s", fname));
200 rc = 210; goto on_return;
201 }
202
203 vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
204 0,
205 PJMEDIA_TYPE_VIDEO);
206 vid_port = pjmedia_avi_stream_get_port(vid_stream);
207
208 if (vid_port) {
209 pjmedia_vid_port_param_default(&param);
210
211 status = pjmedia_vid_dev_default_param(pool,
212 PJMEDIA_VID_DEFAULT_RENDER_DEV,
213 &param.vidparam);
214 if (status != PJ_SUCCESS) {
215 rc = 220; goto on_return;
216 }
217
218 /* Create renderer, set it to active */
219 param.active = PJ_TRUE;
220 param.vidparam.dir = PJMEDIA_DIR_RENDER;
221 vfd = pjmedia_format_get_video_format_detail(&vid_port->info.fmt,
222 PJ_TRUE);
223 pjmedia_format_init_video(&param.vidparam.fmt,
224 vid_port->info.fmt.id,
225 vfd->size.w, vfd->size.h,
226 vfd->fps.num, vfd->fps.denum);
227
228 vfi = pjmedia_get_video_format_info(
229 pjmedia_video_format_mgr_instance(),
230 vid_port->info.fmt.id);
231 /* Check whether the frame is encoded */
232 if (!vfi || vfi->bpp == 0) {
233 /* Yes, prepare codec */
234 pj_str_t codec_id_st;
235 unsigned info_cnt = 1, i, k;
236 const pjmedia_vid_codec_info *codec_info;
237 pj_str_t port_name = {"codec", 5};
238 pj_uint8_t *enc_buf = NULL;
239 pj_size_t enc_buf_size = 0;
240 pjmedia_vid_dev_info rdr_info;
241 pjmedia_port codec_port;
242 codec_port_data_t codec_port_data;
243 pjmedia_vid_codec_param codec_param;
244 struct codec_fmt *codecp = NULL;
245
246 /* Lookup codec */
247 for (i = 0; i < sizeof(codec_fmts)/sizeof(codec_fmts[0]); i++) {
248 if (vid_port->info.fmt.id == codec_fmts[i].pjmedia_id) {
249 codecp = &codec_fmts[i];
250 break;
251 }
252 }
253 if (!codecp) {
254 rc = 242; goto on_return;
255 }
256 pj_cstr(&codec_id_st, codecp->codec_id);
257 status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
258 &codec_id_st,
259 &info_cnt,
260 &codec_info,
261 NULL);
262 if (status != PJ_SUCCESS) {
263 rc = 245; goto on_return;
264 }
265 status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
266 &codec_param);
267 if (status != PJ_SUCCESS) {
268 rc = 246; goto on_return;
269 }
270
271 pjmedia_vid_dev_get_info(param.vidparam.rend_id, &rdr_info);
272 for (i=0; i<codec_info->dec_fmt_id_cnt; ++i) {
273 for (k=0; k<rdr_info.fmt_cnt; ++k) {
274 if (codec_info->dec_fmt_id[i]==(int)rdr_info.fmt[k].id)
275 {
276 param.vidparam.fmt.id = codec_info->dec_fmt_id[i];
277 }
278 }
279 }
280
281 /* Open codec */
282 status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
283 &codec);
284 if (status != PJ_SUCCESS) {
285 rc = 250; goto on_return;
286 }
287
288 status = codec->op->init(codec, pool);
289 if (status != PJ_SUCCESS) {
290 rc = 251; goto on_return;
291 }
292
293 pjmedia_format_copy(&codec_param.dec_fmt, &param.vidparam.fmt);
294
295 status = codec->op->open(codec, &codec_param);
296 if (status != PJ_SUCCESS) {
297 rc = 252; goto on_return;
298 }
299
300 /* Alloc encoding buffer */
301 enc_buf_size = codec_param.dec_fmt.det.vid.size.w *
302 codec_param.dec_fmt.det.vid.size.h * 4
303 + 16; /*< padding, just in case */
304 enc_buf = pj_pool_alloc(pool,enc_buf_size);
305
306 /* Init codec port */
307 pj_bzero(&codec_port, sizeof(codec_port));
308 status = pjmedia_port_info_init2(&codec_port.info, &port_name,
309 0x1234,
310 PJMEDIA_DIR_ENCODING,
311 &codec_param.dec_fmt);
312 if (status != PJ_SUCCESS) {
313 rc = 260; goto on_return;
314 }
315 pj_bzero(&codec_port_data, sizeof(codec_port_data));
316 codec_port_data.codec = codec;
317 codec_port_data.src_port = vid_port;
318 codec_port_data.enc_buf = enc_buf;
319 codec_port_data.enc_buf_size = enc_buf_size;
320
321 codec_port.get_frame = &codec_get_frame;
322 codec_port.port_data.pdata = &codec_port_data;
323
324 /* Check whether we need to convert the decoded frame */
325 if (codecp->need_conversion) {
326 pjmedia_conversion_param conv_param;
327
Sauw Mingb1b17d22010-12-20 11:02:48 +0000328 pjmedia_format_copy(&conv_param.src, &param.vidparam.fmt);
329 pjmedia_format_copy(&conv_param.dst, &param.vidparam.fmt);
330 conv_param.dst.id = codecp->dst_fmt;
331 param.vidparam.fmt.id = conv_param.dst.id;
332
333 status = pjmedia_converter_create(NULL, pool, &conv_param,
334 &codec_port_data.conv);
335 if (status != PJ_SUCCESS) {
336 rc = 270; goto on_return;
337 }
338 }
339
340 status = pjmedia_vid_port_create(pool, &param, &renderer);
341 if (status != PJ_SUCCESS) {
342 rc = 230; goto on_return;
343 }
344
345 status = pjmedia_vid_port_connect(renderer, &codec_port,
346 PJ_FALSE);
347 } else {
348 status = pjmedia_vid_port_create(pool, &param, &renderer);
349 if (status != PJ_SUCCESS) {
350 rc = 230; goto on_return;
351 }
352
353 /* Connect avi port to renderer */
354 status = pjmedia_vid_port_connect(renderer, vid_port,
355 PJ_FALSE);
356 }
357
358 if (status != PJ_SUCCESS) {
359 rc = 240; goto on_return;
360 }
361 }
362
363 aud_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
364 0,
365 PJMEDIA_TYPE_AUDIO);
366 aud_port = pjmedia_avi_stream_get_port(aud_stream);
367
368 if (aud_port) {
Sauw Ming8e799122010-12-30 16:31:16 +0000369 /* Create sound player port. */
370 status = pjmedia_snd_port_create_player(
371 pool, /* pool */
372 -1, /* use default dev. */
373 PJMEDIA_PIA_SRATE(&aud_port->info),/* clock rate. */
374 PJMEDIA_PIA_CCNT(&aud_port->info), /* # of channels. */
375 PJMEDIA_PIA_SPF(&aud_port->info), /* samples per frame. */
376 PJMEDIA_PIA_BITS(&aud_port->info), /* bits per sample. */
377 0, /* options */
378 &snd_port /* returned port */
379 );
Sauw Mingb1b17d22010-12-20 11:02:48 +0000380 if (status != PJ_SUCCESS) {
381 rc = 310; goto on_return;
382 }
383
Sauw Ming8e799122010-12-30 16:31:16 +0000384 /* Connect file port to the sound player.
385 * Stream playing will commence immediately.
386 */
387 status = pjmedia_snd_port_connect(snd_port, aud_port);
Sauw Mingb1b17d22010-12-20 11:02:48 +0000388 if (status != PJ_SUCCESS) {
389 rc = 330; goto on_return;
390 }
391 }
392
393 if (vid_port) {
394 pjmedia_vid_cb cb;
395
396 pj_bzero(&cb, sizeof(cb));
397 cb.on_event_cb = avi_event_cb;
Sauw Ming8e799122010-12-30 16:31:16 +0000398 avi_port.snd_port = snd_port;
Sauw Mingb1b17d22010-12-20 11:02:48 +0000399 avi_port.vid_port = renderer;
400 avi_port.is_running = PJ_TRUE;
401 pjmedia_vid_port_set_cb(renderer, &cb, &avi_port);
Sauw Ming8e799122010-12-30 16:31:16 +0000402
403 if (snd_port) {
404 /* Synchronize video rendering and audio playback */
405 pjmedia_vid_port_set_clock_src(
406 renderer, PJMEDIA_DIR_RENDER,
407 pjmedia_snd_port_get_clock_src(
408 snd_port, PJMEDIA_DIR_PLAYBACK));
409 }
410
Sauw Mingb1b17d22010-12-20 11:02:48 +0000411
412 /* Start video streaming.. */
413 status = pjmedia_vid_port_start(renderer);
414 if (status != PJ_SUCCESS) {
415 rc = 270; goto on_return;
416 }
417 }
418
419 while (!avi_port.is_quitting) {
420 pj_thread_sleep(100);
421 }
422
423on_return:
Sauw Ming8e799122010-12-30 16:31:16 +0000424 if (snd_port) {
425 pjmedia_snd_port_disconnect(snd_port);
426 /* Without this sleep, Windows/DirectSound will repeteadly
427 * play the last frame during destroy.
428 */
429 pj_thread_sleep(100);
430 pjmedia_snd_port_destroy(snd_port);
Sauw Mingb1b17d22010-12-20 11:02:48 +0000431 }
432 if (renderer)
433 pjmedia_vid_port_destroy(renderer);
Sauw Ming8e799122010-12-30 16:31:16 +0000434 if (aud_port)
435 pjmedia_port_destroy(aud_port);
Sauw Mingb1b17d22010-12-20 11:02:48 +0000436 if (vid_port)
437 pjmedia_port_destroy(vid_port);
438 if (codec) {
439 codec->op->close(codec);
440 pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
441 }
442
443 return rc;
444}
445
446
447/*
448 * main()
449 */
450int main(int argc, char *argv[])
451{
452 pj_caching_pool cp;
453 pj_pool_t *pool;
454 int rc = 0;
455 pj_status_t status = PJ_SUCCESS;
456
457 if (argc != 2) {
458 puts("Error: filename required");
459 puts(desc);
460 return 1;
461 }
462
463
464 /* Must init PJLIB first: */
465 status = pj_init();
466 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
467
468 /* Must create a pool factory before we can allocate any memory. */
469 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
470
471 /* Create memory pool for our file player */
472 pool = pj_pool_create( &cp.factory, /* pool factory */
473 "AVI", /* pool name. */
474 4000, /* init size */
475 4000, /* increment size */
476 NULL /* callback on error */
477 );
478
479 pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
480 pjmedia_converter_mgr_create(pool, NULL);
481 pjmedia_vid_codec_mgr_create(pool, NULL);
482
483 status = pjmedia_vid_subsys_init(&cp.factory);
484 if (status != PJ_SUCCESS)
485 goto on_return;
486
487 status = pjmedia_aud_subsys_init(&cp.factory);
488 if (status != PJ_SUCCESS) {
489 goto on_return;
490 }
491
492 status = pjmedia_codec_ffmpeg_init(NULL, &cp.factory);
493 if (status != PJ_SUCCESS)
494 goto on_return;
495
496 rc = aviplay(pool, argv[1]);
497
498 /*
499 * File should be playing and looping now
500 */
501
502 /* Without this sleep, Windows/DirectSound will repeteadly
503 * play the last frame during destroy.
504 */
505 pj_thread_sleep(100);
506
507on_return:
508 pjmedia_codec_ffmpeg_deinit();
509 pjmedia_aud_subsys_shutdown();
510 pjmedia_vid_subsys_shutdown();
511
512 pjmedia_video_format_mgr_destroy(pjmedia_video_format_mgr_instance());
513 pjmedia_converter_mgr_destroy(pjmedia_converter_mgr_instance());
514 pjmedia_vid_codec_mgr_destroy(pjmedia_vid_codec_mgr_instance());
515
516 /* Release application pool */
517 pj_pool_release( pool );
518
519 /* Destroy pool factory */
520 pj_caching_pool_destroy( &cp );
521
522 /* Shutdown PJLIB */
523 pj_shutdown();
524
525 /* Done. */
526 return 0;
527}