BLOG | DOCUMENTATION | TRAC

Home --> Documentations --> PJMEDIA Reference

Samples: Video Streaming

This example mainly demonstrates how to stream video to remote peer using RTP.

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

1 /* $Id: vid_streamutil.c 5747 2018-02-26 10:14:27Z nanang $ */
2 /*
3  * Copyright (C) 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 
32 #include <pjlib.h>
33 #include <pjlib-util.h>
34 #include <pjmedia.h>
35 #include <pjmedia-codec.h>
36 #include <pjmedia/transport_srtp.h>
37 
38 
39 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
40 
41 
42 #include <stdlib.h> /* atoi() */
43 #include <stdio.h>
44 
45 #include "util.h"
46 
47 
48 static const char *desc =
49  " vid_streamutil \n"
50  "\n"
51  " PURPOSE: \n"
52  " Demonstrate how to use pjmedia video stream component to \n"
53  " transmit/receive RTP packets to/from video device/file. \n"
54  "\n"
55  "\n"
56  " USAGE: \n"
57  " vid_streamutil [options] \n"
58  "\n"
59  "\n"
60  " Options: \n"
61  " --codec=CODEC Set the codec name. \n"
62  " --local-port=PORT Set local RTP port (default=4000) \n"
63  " --remote=IP:PORT Set the remote peer. If this option is set, \n"
64  " the program will transmit RTP audio to the \n"
65  " specified address. (default: recv only) \n"
66  " --play-file=AVI Send video from the AVI file instead of from \n"
67  " the video device. \n"
68  " --send-recv Set stream direction to bidirectional. \n"
69  " --send-only Set stream direction to send only \n"
70  " --recv-only Set stream direction to recv only (default) \n"
71 
72  " --send-width Video width to be sent \n"
73  " --send-height Video height to be sent \n"
74  " --send-width and --send-height not applicable \n"
75  " for file streaming (see --play-file) \n"
76 
77  " --send-pt Payload type for sending \n"
78  " --recv-pt Payload type for receiving \n"
79 
80 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
81  " --use-srtp[=NAME] Enable SRTP with crypto suite NAME \n"
82  " e.g: AES_CM_128_HMAC_SHA1_80 (default), \n"
83  " AES_CM_128_HMAC_SHA1_32 \n"
84  " Use this option along with the TX & RX keys, \n"
85  " formated of 60 hex digits (e.g: E148DA..) \n"
86  " --srtp-tx-key SRTP key for transmiting \n"
87  " --srtp-rx-key SRTP key for receiving \n"
88 #endif
89 
90  "\n"
91 ;
92 
93 #define THIS_FILE "vid_streamutil.c"
94 
95 
96 /* If set, local renderer will be created to play original file */
97 #define HAS_LOCAL_RENDERER_FOR_PLAY_FILE 1
98 
99 
100 /* Default width and height for the renderer, better be set to maximum
101  * acceptable size.
102  */
103 #define DEF_RENDERER_WIDTH 640
104 #define DEF_RENDERER_HEIGHT 480
105 
106 
107 /* Prototype */
108 static void print_stream_stat(pjmedia_vid_stream *stream,
109  const pjmedia_vid_codec_param *codec_param);
110 
111 /* Hexa string to octet array */
112 int my_hex_string_to_octet_string(char *raw, char *hex, int len)
113 {
114  int i;
115  for (i = 0; i < len; i+=2) {
116  int tmp;
117  if (i+1 >= len || !pj_isxdigit(hex[i]) || !pj_isxdigit(hex[i+1]))
118  return i;
119  tmp = pj_hex_digit_to_val((unsigned char)hex[i]) << 4;
120  tmp |= pj_hex_digit_to_val((unsigned char)hex[i+1]);
121  raw[i/2] = (char)(tmp & 0xFF);
122  }
123  return len;
124 }
125 
126 /*
127  * Register all codecs.
128  */
129 static pj_status_t init_codecs(pj_pool_factory *pf)
130 {
131  pj_status_t status;
132 
133  /* To suppress warning about unused var when all codecs are disabled */
134  PJ_UNUSED_ARG(status);
135 
136 #if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
137  status = pjmedia_codec_openh264_vid_init(NULL, pf);
138  PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
139 #endif
140 
141 #if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
142  status = pjmedia_codec_ffmpeg_vid_init(NULL, pf);
143  PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
144 #endif
145 
146  return PJ_SUCCESS;
147 }
148 
149 /*
150  * Register all codecs.
151  */
152 static void deinit_codecs()
153 {
154 #if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC != 0
156 #endif
157 
158 #if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
160 #endif
161 
162 }
163 
164 static pj_status_t create_file_player( pj_pool_t *pool,
165  const char *file_name,
166  pjmedia_port **p_play_port)
167 {
168  pjmedia_avi_streams *avi_streams;
169  pjmedia_avi_stream *vid_stream;
170  pjmedia_port *play_port;
171  pj_status_t status;
172 
173  status = pjmedia_avi_player_create_streams(pool, file_name, 0, &avi_streams);
174  if (status != PJ_SUCCESS)
175  return status;
176 
177  vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
178  0,
180  if (!vid_stream)
181  return PJ_ENOTFOUND;
182 
183  play_port = pjmedia_avi_stream_get_port(vid_stream);
184  pj_assert(play_port);
185 
186  *p_play_port = play_port;
187 
188  return PJ_SUCCESS;
189 }
190 
191 /*
192  * Create stream based on the codec, dir, remote address, etc.
193  */
194 static pj_status_t create_stream( pj_pool_t *pool,
195  pjmedia_endpt *med_endpt,
196  const pjmedia_vid_codec_info *codec_info,
197  pjmedia_vid_codec_param *codec_param,
198  pjmedia_dir dir,
199  pj_int8_t rx_pt,
200  pj_int8_t tx_pt,
201  pj_uint16_t local_port,
202  const pj_sockaddr_in *rem_addr,
203 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
204  pj_bool_t use_srtp,
205  const pj_str_t *crypto_suite,
206  const pj_str_t *srtp_tx_key,
207  const pj_str_t *srtp_rx_key,
208 #endif
209  pjmedia_vid_stream **p_stream )
210 {
212  pjmedia_transport *transport = NULL;
213  pj_status_t status;
214 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
215  pjmedia_transport *srtp_tp = NULL;
216 #endif
217 
218  /* Reset stream info. */
219  pj_bzero(&info, sizeof(info));
220 
221  /* Initialize stream info formats */
222  info.type = PJMEDIA_TYPE_VIDEO;
223  info.dir = dir;
224  info.codec_info = *codec_info;
225  info.tx_pt = (tx_pt == -1)? codec_info->pt : tx_pt;
226  info.rx_pt = (rx_pt == -1)? codec_info->pt : rx_pt;
227  info.ssrc = pj_rand();
228  if (codec_param)
229  info.codec_param = codec_param;
230 
231  /* Copy remote address */
232  pj_memcpy(&info.rem_addr, rem_addr, sizeof(pj_sockaddr_in));
233 
234  /* If remote address is not set, set to an arbitrary address
235  * (otherwise stream will assert).
236  */
237  if (info.rem_addr.addr.sa_family == 0) {
238  const pj_str_t addr = pj_str("127.0.0.1");
239  pj_sockaddr_in_init(&info.rem_addr.ipv4, &addr, 0);
240  }
241 
242  /* Create media transport */
243  status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
244  0, &transport);
245  if (status != PJ_SUCCESS)
246  return status;
247 
248 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
249  /* Check if SRTP enabled */
250  if (use_srtp) {
251  pjmedia_srtp_crypto tx_plc, rx_plc;
252 
253  status = pjmedia_transport_srtp_create(med_endpt, transport,
254  NULL, &srtp_tp);
255  if (status != PJ_SUCCESS)
256  return status;
257 
258  pj_bzero(&tx_plc, sizeof(pjmedia_srtp_crypto));
259  pj_bzero(&rx_plc, sizeof(pjmedia_srtp_crypto));
260 
261  tx_plc.key = *srtp_tx_key;
262  tx_plc.name = *crypto_suite;
263  rx_plc.key = *srtp_rx_key;
264  rx_plc.name = *crypto_suite;
265 
266  status = pjmedia_transport_srtp_start(srtp_tp, &tx_plc, &rx_plc);
267  if (status != PJ_SUCCESS)
268  return status;
269 
270  transport = srtp_tp;
271  }
272 #endif
273 
274  /* Now that the stream info is initialized, we can create the
275  * stream.
276  */
277 
278  status = pjmedia_vid_stream_create( med_endpt, pool, &info,
279  transport,
280  NULL, p_stream);
281 
282  if (status != PJ_SUCCESS) {
283  app_perror(THIS_FILE, "Error creating stream", status);
284  pjmedia_transport_close(transport);
285  return status;
286  }
287 
288  /* Start media transport */
289  pjmedia_transport_media_start(transport, 0, 0, 0, 0);
290 
291  return PJ_SUCCESS;
292 }
293 
294 
295 typedef struct play_file_data
296 {
297  const char *file_name;
298  pjmedia_port *play_port;
299  pjmedia_port *stream_port;
300  pjmedia_vid_codec *decoder;
301  pjmedia_port *renderer;
302  void *read_buf;
303  pj_size_t read_buf_size;
304  void *dec_buf;
305  pj_size_t dec_buf_size;
306 } play_file_data;
307 
308 
309 static void clock_cb(const pj_timestamp *ts, void *user_data)
310 {
311  play_file_data *play_file = (play_file_data*)user_data;
312  pjmedia_frame read_frame, write_frame;
313  pj_status_t status;
314 
315  PJ_UNUSED_ARG(ts);
316 
317  /* Read frame from file */
318  read_frame.buf = play_file->read_buf;
319  read_frame.size = play_file->read_buf_size;
320  pjmedia_port_get_frame(play_file->play_port, &read_frame);
321 
322  /* Decode frame, if needed */
323  if (play_file->decoder) {
324  pjmedia_vid_codec *decoder = play_file->decoder;
325 
326  write_frame.buf = play_file->dec_buf;
327  write_frame.size = play_file->dec_buf_size;
328  status = pjmedia_vid_codec_decode(decoder, 1, &read_frame,
329  (unsigned)write_frame.size,
330  &write_frame);
331  if (status != PJ_SUCCESS)
332  return;
333  } else {
334  write_frame = read_frame;
335  }
336 
337  /* Display frame locally */
338  if (play_file->renderer)
339  pjmedia_port_put_frame(play_file->renderer, &write_frame);
340 
341  /* Send frame */
342  pjmedia_port_put_frame(play_file->stream_port, &write_frame);
343 }
344 
345 
346 /*
347  * usage()
348  */
349 static void usage()
350 {
351  puts(desc);
352 }
353 
354 /*
355  * main()
356  */
357 int main(int argc, char *argv[])
358 {
359  pj_caching_pool cp;
360  pjmedia_endpt *med_endpt;
361  pj_pool_t *pool;
362  pjmedia_vid_stream *stream = NULL;
363  pjmedia_port *enc_port, *dec_port;
364  char addr[PJ_INET_ADDRSTRLEN];
365  pj_status_t status;
366 
367  pjmedia_vid_port *capture=NULL, *renderer=NULL;
369 
370 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
371  /* SRTP variables */
372  pj_bool_t use_srtp = PJ_FALSE;
373  char tmp_tx_key[64];
374  char tmp_rx_key[64];
375  pj_str_t srtp_tx_key = {NULL, 0};
376  pj_str_t srtp_rx_key = {NULL, 0};
377  pj_str_t srtp_crypto_suite = {NULL, 0};
378  int tmp_key_len;
379 #endif
380 
381  /* Default values */
382  const pjmedia_vid_codec_info *codec_info;
383  pjmedia_vid_codec_param codec_param;
385  pj_sockaddr_in remote_addr;
386  pj_uint16_t local_port = 4000;
387  char *codec_id = NULL;
388  pjmedia_rect_size tx_size = {0};
389  pj_int8_t rx_pt = -1, tx_pt = -1;
390 
391  play_file_data play_file = { NULL };
392  pjmedia_port *play_port = NULL;
393  pjmedia_vid_codec *play_decoder = NULL;
394  pjmedia_clock *play_clock = NULL;
395 
396  enum {
397  OPT_CODEC = 'c',
398  OPT_LOCAL_PORT = 'p',
399  OPT_REMOTE = 'r',
400  OPT_PLAY_FILE = 'f',
401  OPT_SEND_RECV = 'b',
402  OPT_SEND_ONLY = 's',
403  OPT_RECV_ONLY = 'i',
404  OPT_SEND_WIDTH = 'W',
405  OPT_SEND_HEIGHT = 'H',
406  OPT_RECV_PT = 't',
407  OPT_SEND_PT = 'T',
408 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
409  OPT_USE_SRTP = 'S',
410 #endif
411  OPT_SRTP_TX_KEY = 'x',
412  OPT_SRTP_RX_KEY = 'y',
413  OPT_HELP = 'h',
414  };
415 
416  struct pj_getopt_option long_options[] = {
417  { "codec", 1, 0, OPT_CODEC },
418  { "local-port", 1, 0, OPT_LOCAL_PORT },
419  { "remote", 1, 0, OPT_REMOTE },
420  { "play-file", 1, 0, OPT_PLAY_FILE },
421  { "send-recv", 0, 0, OPT_SEND_RECV },
422  { "send-only", 0, 0, OPT_SEND_ONLY },
423  { "recv-only", 0, 0, OPT_RECV_ONLY },
424  { "send-width", 1, 0, OPT_SEND_WIDTH },
425  { "send-height", 1, 0, OPT_SEND_HEIGHT },
426  { "recv-pt", 1, 0, OPT_RECV_PT },
427  { "send-pt", 1, 0, OPT_SEND_PT },
428 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
429  { "use-srtp", 2, 0, OPT_USE_SRTP },
430  { "srtp-tx-key", 1, 0, OPT_SRTP_TX_KEY },
431  { "srtp-rx-key", 1, 0, OPT_SRTP_RX_KEY },
432 #endif
433  { "help", 0, 0, OPT_HELP },
434  { NULL, 0, 0, 0 },
435  };
436 
437  int c;
438  int option_index;
439 
440 
441  pj_bzero(&remote_addr, sizeof(remote_addr));
442 
443 
444  /* init PJLIB : */
445  status = pj_init();
446  PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
447 
448 
449  /* Parse arguments */
450  pj_optind = 0;
451  while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1)
452  {
453  switch (c) {
454  case OPT_CODEC:
455  codec_id = pj_optarg;
456  break;
457 
458  case OPT_LOCAL_PORT:
459  local_port = (pj_uint16_t) atoi(pj_optarg);
460  if (local_port < 1) {
461  printf("Error: invalid local port %s\n", pj_optarg);
462  return 1;
463  }
464  break;
465 
466  case OPT_REMOTE:
467  {
468  pj_str_t ip = pj_str(strtok(pj_optarg, ":"));
469  pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":"));
470 
471  status = pj_sockaddr_in_init(&remote_addr, &ip, port);
472  if (status != PJ_SUCCESS) {
473  app_perror(THIS_FILE, "Invalid remote address", status);
474  return 1;
475  }
476  }
477  break;
478 
479  case OPT_PLAY_FILE:
480  play_file.file_name = pj_optarg;
481  break;
482 
483  case OPT_SEND_RECV:
485  break;
486 
487  case OPT_SEND_ONLY:
488  dir = PJMEDIA_DIR_ENCODING;
489  break;
490 
491  case OPT_RECV_ONLY:
492  dir = PJMEDIA_DIR_DECODING;
493  break;
494 
495  case OPT_SEND_WIDTH:
496  tx_size.w = (unsigned)atoi(pj_optarg);
497  break;
498 
499  case OPT_SEND_HEIGHT:
500  tx_size.h = (unsigned)atoi(pj_optarg);
501  break;
502 
503  case OPT_RECV_PT:
504  rx_pt = (pj_int8_t)atoi(pj_optarg);
505  break;
506 
507  case OPT_SEND_PT:
508  tx_pt = (pj_int8_t)atoi(pj_optarg);
509  break;
510 
511 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
512  case OPT_USE_SRTP:
513  use_srtp = PJ_TRUE;
514  if (pj_optarg) {
515  pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
516  } else {
517  srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
518  }
519  break;
520 
521  case OPT_SRTP_TX_KEY:
522  tmp_key_len = my_hex_string_to_octet_string(tmp_tx_key, pj_optarg,
523  (int)strlen(pj_optarg));
524  pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
525  break;
526 
527  case OPT_SRTP_RX_KEY:
528  tmp_key_len = my_hex_string_to_octet_string(tmp_rx_key, pj_optarg,
529  (int)strlen(pj_optarg));
530  pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
531  break;
532 #endif
533 
534  case OPT_HELP:
535  usage();
536  return 1;
537 
538  default:
539  printf("Invalid options %s\n", argv[pj_optind]);
540  return 1;
541  }
542 
543  }
544 
545 
546  /* Verify arguments. */
547  if (dir & PJMEDIA_DIR_ENCODING) {
548  if (remote_addr.sin_addr.s_addr == 0) {
549  printf("Error: remote address must be set\n");
550  return 1;
551  }
552  }
553 
554  if (play_file.file_name != NULL && dir != PJMEDIA_DIR_ENCODING) {
555  printf("Direction is set to --send-only because of --play-file\n");
556  dir = PJMEDIA_DIR_ENCODING;
557  }
558 
559 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
560  /* SRTP validation */
561  if (use_srtp) {
562  if (!srtp_tx_key.slen || !srtp_rx_key.slen)
563  {
564  printf("Error: Key for each SRTP stream direction must be set\n");
565  return 1;
566  }
567  }
568 #endif
569 
570  /* Must create a pool factory before we can allocate any memory. */
572 
573  /*
574  * Initialize media endpoint.
575  * This will implicitly initialize PJMEDIA too.
576  */
577  status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
578  PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
579 
580  /* Create memory pool for application purpose */
581  pool = pj_pool_create( &cp.factory, /* pool factory */
582  "app", /* pool name. */
583  4000, /* init size */
584  4000, /* increment size */
585  NULL /* callback on error */
586  );
587 
588  /* Init video format manager */
589  pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
590 
591  /* Init video converter manager */
592  pjmedia_converter_mgr_create(pool, NULL);
593 
594  /* Init event manager */
595  pjmedia_event_mgr_create(pool, 0, NULL);
596 
597  /* Init video codec manager */
598  pjmedia_vid_codec_mgr_create(pool, NULL);
599 
600  /* Init video subsystem */
602 
603  /* Register all supported codecs */
604  status = init_codecs(&cp.factory);
605  PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
606 
607 
608  /* Find which codec to use. */
609  if (codec_id) {
610  unsigned count = 1;
611  pj_str_t str_codec_id = pj_str(codec_id);
612 
614  &str_codec_id, &count,
615  &codec_info, NULL);
616  if (status != PJ_SUCCESS) {
617  printf("Error: unable to find codec %s\n", codec_id);
618  return 1;
619  }
620  } else {
621  static pjmedia_vid_codec_info info[1];
622  unsigned count = PJ_ARRAY_SIZE(info);
623 
624  /* Default to first codec */
625  pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL);
626  codec_info = &info[0];
627  }
628 
629  /* Get codec default param for info */
630  status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
631  &codec_param);
632  pj_assert(status == PJ_SUCCESS);
633 
634  /* Set outgoing video size */
635  if (tx_size.w && tx_size.h)
636  codec_param.enc_fmt.det.vid.size = tx_size;
637 
638 #if DEF_RENDERER_WIDTH && DEF_RENDERER_HEIGHT
639  /* Set incoming video size */
640  if (DEF_RENDERER_WIDTH > codec_param.dec_fmt.det.vid.size.w)
641  codec_param.dec_fmt.det.vid.size.w = DEF_RENDERER_WIDTH;
642  if (DEF_RENDERER_HEIGHT > codec_param.dec_fmt.det.vid.size.h)
643  codec_param.dec_fmt.det.vid.size.h = DEF_RENDERER_HEIGHT;
644 #endif
645 
646  if (play_file.file_name) {
647  pjmedia_video_format_detail *file_vfd;
648  pjmedia_clock_param clock_param;
649  char fmt_name[5];
650 
651  /* Create file player */
652  status = create_file_player(pool, play_file.file_name, &play_port);
653  if (status != PJ_SUCCESS)
654  goto on_exit;
655 
656  /* Collect format info */
657  file_vfd = pjmedia_format_get_video_format_detail(&play_port->info.fmt,
658  PJ_TRUE);
659  PJ_LOG(2, (THIS_FILE, "Reading video stream %dx%d %s @%.2ffps",
660  file_vfd->size.w, file_vfd->size.h,
661  pjmedia_fourcc_name(play_port->info.fmt.id, fmt_name),
662  (1.0*file_vfd->fps.num/file_vfd->fps.denum)));
663 
664  /* Allocate file read buffer */
665  play_file.read_buf_size = PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE;
666  play_file.read_buf = pj_pool_zalloc(pool, play_file.read_buf_size);
667 
668  /* Create decoder, if the file and the stream uses different codec */
669  if (codec_info->fmt_id != (pjmedia_format_id)play_port->info.fmt.id) {
670  const pjmedia_video_format_info *dec_vfi;
671  pjmedia_video_apply_fmt_param dec_vafp = {0};
672  const pjmedia_vid_codec_info *codec_info2;
673  pjmedia_vid_codec_param codec_param2;
674 
675  /* Find decoder */
677  play_port->info.fmt.id,
678  &codec_info2);
679  if (status != PJ_SUCCESS)
680  goto on_exit;
681 
682  /* Init decoder */
683  status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info2,
684  &play_decoder);
685  if (status != PJ_SUCCESS)
686  goto on_exit;
687 
688  status = play_decoder->op->init(play_decoder, pool);
689  if (status != PJ_SUCCESS)
690  goto on_exit;
691 
692  /* Open decoder */
693  status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info2,
694  &codec_param2);
695  if (status != PJ_SUCCESS)
696  goto on_exit;
697 
698  codec_param2.dir = PJMEDIA_DIR_DECODING;
699  status = play_decoder->op->open(play_decoder, &codec_param2);
700  if (status != PJ_SUCCESS)
701  goto on_exit;
702 
703  /* Get decoder format info and apply param */
704  dec_vfi = pjmedia_get_video_format_info(NULL,
705  codec_info2->dec_fmt_id[0]);
706  if (!dec_vfi || !dec_vfi->apply_fmt) {
707  status = PJ_ENOTSUP;
708  goto on_exit;
709  }
710  dec_vafp.size = file_vfd->size;
711  (*dec_vfi->apply_fmt)(dec_vfi, &dec_vafp);
712 
713  /* Allocate buffer to receive decoder output */
714  play_file.dec_buf_size = dec_vafp.framebytes;
715  play_file.dec_buf = pj_pool_zalloc(pool, play_file.dec_buf_size);
716  }
717 
718  /* Create player clock */
719  clock_param.usec_interval = PJMEDIA_PTIME(&file_vfd->fps);
720  clock_param.clock_rate = codec_info->clock_rate;
721  status = pjmedia_clock_create2(pool, &clock_param,
723  &clock_cb, &play_file, &play_clock);
724  if (status != PJ_SUCCESS)
725  goto on_exit;
726 
727  /* Override stream codec param for encoding direction */
728  codec_param.enc_fmt.det.vid.size = file_vfd->size;
729  codec_param.enc_fmt.det.vid.fps = file_vfd->fps;
730 
731  } else {
733 
734  /* Set as active for all video devices */
735  vpp.active = PJ_TRUE;
736 
737  /* Create video device port. */
738  if (dir & PJMEDIA_DIR_ENCODING) {
739  /* Create capture */
741  pool,
743  &vpp.vidparam);
744  if (status != PJ_SUCCESS)
745  goto on_exit;
746 
747  pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.enc_fmt);
748  vpp.vidparam.fmt.id = codec_param.dec_fmt.id;
750 
751  status = pjmedia_vid_port_create(pool, &vpp, &capture);
752  if (status != PJ_SUCCESS)
753  goto on_exit;
754  }
755 
756  if (dir & PJMEDIA_DIR_DECODING) {
757  /* Create renderer */
759  pool,
761  &vpp.vidparam);
762  if (status != PJ_SUCCESS)
763  goto on_exit;
764 
765  pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
771 
772  status = pjmedia_vid_port_create(pool, &vpp, &renderer);
773  if (status != PJ_SUCCESS)
774  goto on_exit;
775  }
776  }
777 
778  /* Set to ignore fmtp */
779  codec_param.ignore_fmtp = PJ_TRUE;
780 
781  /* Create stream based on program arguments */
782  status = create_stream(pool, med_endpt, codec_info, &codec_param,
783  dir, rx_pt, tx_pt, local_port, &remote_addr,
784 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
785  use_srtp, &srtp_crypto_suite,
786  &srtp_tx_key, &srtp_rx_key,
787 #endif
788  &stream);
789  if (status != PJ_SUCCESS)
790  goto on_exit;
791 
792  /* Get the port interface of the stream */
793  status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_ENCODING,
794  &enc_port);
795  PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
796 
797  status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_DECODING,
798  &dec_port);
799  PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
800 
801  /* Start streaming */
802  status = pjmedia_vid_stream_start(stream);
803  if (status != PJ_SUCCESS)
804  goto on_exit;
805 
806  /* Start renderer */
807  if (renderer) {
808  status = pjmedia_vid_port_connect(renderer, dec_port, PJ_FALSE);
809  if (status != PJ_SUCCESS)
810  goto on_exit;
811  status = pjmedia_vid_port_start(renderer);
812  if (status != PJ_SUCCESS)
813  goto on_exit;
814  }
815 
816  /* Start capture */
817  if (capture) {
818  status = pjmedia_vid_port_connect(capture, enc_port, PJ_FALSE);
819  if (status != PJ_SUCCESS)
820  goto on_exit;
821  status = pjmedia_vid_port_start(capture);
822  if (status != PJ_SUCCESS)
823  goto on_exit;
824  }
825 
826  /* Start playing file */
827  if (play_file.file_name) {
828 
829 #if HAS_LOCAL_RENDERER_FOR_PLAY_FILE
830  /* Create local renderer */
832  vpp.active = PJ_FALSE;
834  pool,
836  &vpp.vidparam);
837  if (status != PJ_SUCCESS)
838  goto on_exit;
839 
841  pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
842  vpp.vidparam.fmt.det.vid.size = play_port->info.fmt.det.vid.size;
843  vpp.vidparam.fmt.det.vid.fps = play_port->info.fmt.det.vid.fps;
848 
849  status = pjmedia_vid_port_create(pool, &vpp, &renderer);
850  if (status != PJ_SUCCESS)
851  goto on_exit;
852  status = pjmedia_vid_port_start(renderer);
853  if (status != PJ_SUCCESS)
854  goto on_exit;
855 #endif
856 
857  /* Init play file data */
858  play_file.play_port = play_port;
859  play_file.stream_port = enc_port;
860  play_file.decoder = play_decoder;
861  if (renderer) {
862  play_file.renderer = pjmedia_vid_port_get_passive_port(renderer);
863  }
864 
865  status = pjmedia_clock_start(play_clock);
866  if (status != PJ_SUCCESS)
867  goto on_exit;
868  }
869 
870  /* Done */
871 
872  if (dir == PJMEDIA_DIR_DECODING)
873  printf("Stream is active, dir is recv-only, local port is %d\n",
874  local_port);
875  else if (dir == PJMEDIA_DIR_ENCODING)
876  printf("Stream is active, dir is send-only, sending to %s:%d\n",
877  pj_inet_ntop2(pj_AF_INET(), &remote_addr.sin_addr, addr,
878  sizeof(addr)),
879  pj_ntohs(remote_addr.sin_port));
880  else
881  printf("Stream is active, send/recv, local port is %d, "
882  "sending to %s:%d\n",
883  local_port,
884  pj_inet_ntop2(pj_AF_INET(), &remote_addr.sin_addr, addr,
885  sizeof(addr)),
886  pj_ntohs(remote_addr.sin_port));
887 
888  if (dir & PJMEDIA_DIR_ENCODING)
889  PJ_LOG(2, (THIS_FILE, "Sending %dx%d %.*s @%.2ffps",
890  codec_param.enc_fmt.det.vid.size.w,
891  codec_param.enc_fmt.det.vid.size.h,
892  codec_info->encoding_name.slen,
893  codec_info->encoding_name.ptr,
894  (1.0*codec_param.enc_fmt.det.vid.fps.num/
895  codec_param.enc_fmt.det.vid.fps.denum)));
896 
897  for (;;) {
898  char tmp[10];
899 
900  puts("");
901  puts("Commands:");
902  puts(" q Quit");
903  puts("");
904 
905  printf("Command: "); fflush(stdout);
906 
907  if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
908  puts("EOF while reading stdin, will quit now..");
909  break;
910  }
911 
912  if (tmp[0] == 'q')
913  break;
914 
915  }
916 
917 
918 
919  /* Start deinitialization: */
920 on_exit:
921 
922  /* Stop video devices */
923  if (capture)
924  pjmedia_vid_port_stop(capture);
925  if (renderer)
926  pjmedia_vid_port_stop(renderer);
927 
928  /* Stop and destroy file clock */
929  if (play_clock) {
930  pjmedia_clock_stop(play_clock);
931  pjmedia_clock_destroy(play_clock);
932  }
933 
934  /* Destroy file reader/player */
935  if (play_port)
936  pjmedia_port_destroy(play_port);
937 
938  /* Destroy file decoder */
939  if (play_decoder) {
940  play_decoder->op->close(play_decoder);
941  pjmedia_vid_codec_mgr_dealloc_codec(NULL, play_decoder);
942  }
943 
944  /* Destroy video devices */
945  if (capture)
946  pjmedia_vid_port_destroy(capture);
947  if (renderer)
948  pjmedia_vid_port_destroy(renderer);
949 
950  /* Destroy stream */
951  if (stream) {
952  pjmedia_transport *tp;
953 
956 
958  }
959 
960  /* Deinit codecs */
961  deinit_codecs();
962 
963  /* Shutdown video subsystem */
965 
966  /* Destroy event manager */
968 
969  /* Release application pool */
970  pj_pool_release( pool );
971 
972  /* Destroy media endpoint. */
973  pjmedia_endpt_destroy( med_endpt );
974 
975  /* Destroy pool factory */
977 
978  /* Shutdown PJLIB */
979  pj_shutdown();
980 
981  return (status == PJ_SUCCESS) ? 0 : 1;
982 }
983 
984 
985 #else
986 
987 int main(int argc, char *argv[])
988 {
989  PJ_UNUSED_ARG(argc);
990  PJ_UNUSED_ARG(argv);
991  puts("Error: this sample requires video capability (PJMEDIA_HAS_VIDEO == 1)");
992  return -1;
993 }
994 
995 #endif /* PJMEDIA_HAS_VIDEO */
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(* open)(pjmedia_vid_codec *codec, pjmedia_vid_codec_param *param)
Definition: vid_codec.h:201
pj_status_t pjmedia_transport_close(pjmedia_transport *tp)
Definition: transport.h:993
PJMEDIA main header file.
pj_str_t key
Definition: transport_srtp.h:94
pj_ssize_t slen
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_in_addr sin_addr
unsigned pt
Definition: vid_codec.h:117
#define PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE
Definition: config.h:1339
pj_uint16_t pj_ntohs(pj_uint16_t netshort)
#define PJ_ARRAY_SIZE(a)
unsigned clock_rate
Definition: vid_codec.h:120
pjmedia_format_id fmt_id
Definition: vid_codec.h:116
#define PJ_ASSERT_RETURN(expr, retval)
Definition: videodev.h:152
char * ptr
pj_status_t pjmedia_vid_codec_mgr_dealloc_codec(pjmedia_vid_codec_mgr *mgr, pjmedia_vid_codec *codec)
pj_status_t pjmedia_port_get_frame(pjmedia_port *port, pjmedia_frame *frame)
pj_status_t pjmedia_transport_srtp_start(pjmedia_transport *srtp, const pjmedia_srtp_crypto *tx, const pjmedia_srtp_crypto *rx)
pj_size_t size
Definition: frame.h:60
pjmedia_port_info info
Definition: port.h:366
void pj_pool_release(pj_pool_t *pool)
pj_addr_hdr addr
pjmedia_format_id dec_fmt_id[8]
Definition: vid_codec.h:124
pj_status_t pjmedia_transport_srtp_create(pjmedia_endpt *endpt, pjmedia_transport *tp, const pjmedia_srtp_setting *opt, pjmedia_transport **p_tp)
pjmedia_format fmt
Definition: port.h:234
unsigned usec_interval
Definition: clock.h:189
pj_status_t pjmedia_clock_destroy(pjmedia_clock *clock)
int pj_bool_t
pjmedia_format * pjmedia_format_copy(pjmedia_format *dst, const pjmedia_format *src)
void * pj_memcpy(void *dst, const void *src, pj_size_t size)
pj_uint16_t sin_port
Definition: transport_srtp.h:91
pj_status_t pjmedia_vid_codec_mgr_get_codec_info2(pjmedia_vid_codec_mgr *mgr, pjmedia_format_id fmt_id, const pjmedia_vid_codec_info **info)
int denum
Definition: types.h:219
Definition: vid_stream.h:149
void pjmedia_vid_port_param_default(pjmedia_vid_port_param *prm)
pj_status_t pjmedia_port_destroy(pjmedia_port *port)
unsigned h
Definition: types.h:237
struct pjmedia_endpt pjmedia_endpt
Definition: types.h:187
Definition: types.h:170
pj_status_t pjmedia_vid_stream_create(pjmedia_endpt *endpt, pj_pool_t *pool, pjmedia_vid_stream_info *info, pjmedia_transport *tp, void *user_data, pjmedia_vid_stream **p_stream)
pj_status_t pjmedia_clock_start(pjmedia_clock *clock)
pjmedia_vid_codec_op * op
Definition: vid_codec.h:283
pjmedia_ratio fps
Definition: format.h:265
const pjmedia_video_format_info * pjmedia_get_video_format_info(pjmedia_video_format_mgr *mgr, pj_uint32_t id)
struct pjmedia_vid_port pjmedia_vid_port
Definition: vid_port.h:69
pjmedia_format_id
Definition: format.h:55
pj_bool_t ignore_fmtp
Definition: vid_codec.h:160
pj_status_t pjmedia_video_format_mgr_create(pj_pool_t *pool, unsigned max_fmt, unsigned options, pjmedia_video_format_mgr **p_mgr)
pjmedia_port * pjmedia_vid_port_get_passive_port(pjmedia_vid_port *vid_port)
pjmedia_rect_size size
Definition: format.h:264
pjmedia_dir dir
Definition: vid_stream.h:153
Definition: transport.h:501
pj_status_t pjmedia_vid_stream_start(pjmedia_vid_stream *stream)
#define PJ_ENOTSUP
Definition: videodev.h:276
pj_str_t name
Definition: transport_srtp.h:97
#define PJ_LOG(level, arg)
pj_status_t pjmedia_clock_stop(pjmedia_clock *clock)
int pj_status_t
pj_status_t pjmedia_vid_dev_subsys_shutdown(void)
pjmedia_vid_dev_param vidparam
Definition: vid_port.h:47
pj_pool_factory_policy pj_pool_factory_default_policy
pj_uint16_t sa_family
pj_status_t pjmedia_converter_mgr_create(pj_pool_t *pool, pjmedia_converter_mgr **mgr)
signed char pj_int8_t
unsigned pj_hex_digit_to_val(unsigned char c)
pj_status_t pjmedia_event_mgr_create(pj_pool_t *pool, unsigned options, pjmedia_event_mgr **mgr)
pjmedia_rect_size size
Definition: format.h:357
unsigned window_flags
Definition: videodev.h:465
Definition: format.h:349
Definition: types.h:158
Definition: types.h:164
pj_status_t(* init)(pjmedia_vid_codec *codec, pj_pool_t *pool)
Definition: vid_codec.h:195
pj_status_t pjmedia_vid_codec_mgr_create(pj_pool_t *pool, pjmedia_vid_codec_mgr **mgr)
Secure RTP (SRTP) transport.
int pj_isxdigit(unsigned char c)
Definition: types.h:234
pj_size_t framebytes
Definition: format.h:375
pj_status_t pj_sockaddr_in_init(pj_sockaddr_in *addr, const pj_str_t *cp, pj_uint16_t port)
pj_status_t pjmedia_vid_codec_mgr_enum_codecs(pjmedia_vid_codec_mgr *mgr, unsigned *count, pjmedia_vid_codec_info info[], unsigned *prio)
Definition: port.h:364
pj_str_t info
pj_status_t pjmedia_vid_stream_destroy(pjmedia_vid_stream *stream)
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:826
pj_pool_factory factory
pj_status_t pjmedia_vid_port_connect(pjmedia_vid_port *vid_port, pjmedia_port *port, pj_bool_t destroy)
void pjmedia_event_mgr_destroy(pjmedia_event_mgr *mgr)
pjmedia_video_format_detail vid
Definition: format.h:316
pj_status_t pjmedia_vid_port_stop(pjmedia_vid_port *vid_port)
Include all codecs API in PJMEDIA-CODEC.
pj_uint32_t ssrc
Definition: vid_stream.h:161
pj_status_t pjmedia_transport_udp_create(pjmedia_endpt *endpt, const char *name, int port, unsigned options, pjmedia_transport **p_tp)
#define PJ_ENOTFOUND
unsigned PJMEDIA_PTIME(const pjmedia_ratio *frame_rate)
Definition: format.h:526
PJ_TRUE
#define pj_assert(expr)
pj_status_t(* close)(pjmedia_vid_codec *codec)
Definition: vid_codec.h:207
pjmedia_vid_codec_info codec_info
Definition: vid_stream.h:187
pjmedia_format dec_fmt
Definition: vid_codec.h:157
pj_status_t pjmedia_endpt_create(pj_pool_factory *pf, pj_ioqueue_t *ioqueue, unsigned worker_cnt, pjmedia_endpt **p_endpt)
Definition: endpoint.h:105
pj_status_t pjmedia_codec_ffmpeg_vid_init(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf)
pjmedia_format enc_fmt
Definition: vid_codec.h:153
pj_status_t pjmedia_vid_port_start(pjmedia_vid_port *vid_port)
pj_status_t pjmedia_vid_dev_default_param(pj_pool_t *pool, pjmedia_vid_dev_index id, pjmedia_vid_dev_param *param)
pj_str_t pj_str(char *str)
unsigned tx_pt
Definition: vid_stream.h:159
const char * pjmedia_fourcc_name(pj_uint32_t sig, char buf[])
Definition: types.h:318
pjmedia_type type
Definition: vid_stream.h:151
void pj_caching_pool_init(pj_caching_pool *ch_pool, const pj_pool_factory_policy *policy, pj_size_t max_capacity)
void * buf
Definition: frame.h:59
pjmedia_transport * pjmedia_vid_stream_get_transport(pjmedia_vid_stream *st)
pj_status_t pjmedia_port_put_frame(pjmedia_port *port, pjmedia_frame *frame)
void pj_bzero(void *dst, pj_size_t size)
pj_status_t(* apply_fmt)(const struct pjmedia_video_format_info *vfi, pjmedia_video_apply_fmt_param *vafp)
Definition: format.h:444
pj_sockaddr rem_addr
Definition: vid_stream.h:154
pj_str_t encoding_name
Definition: vid_codec.h:118
pjmedia_rect_size disp_size
Definition: videodev.h:433
pj_status_t pjmedia_codec_openh264_vid_deinit(void)
pj_status_t pjmedia_vid_dev_subsys_init(pj_pool_factory *pf)
pjmedia_avi_stream * pjmedia_avi_streams_get_stream_by_media(pjmedia_avi_streams *streams, unsigned start_idx, pjmedia_type media_type)
pjmedia_vid_codec_param * codec_param
Definition: vid_stream.h:188
#define PJ_INET_ADDRSTRLEN
void pjmedia_vid_port_destroy(pjmedia_vid_port *vid_port)
unsigned rx_pt
Definition: vid_stream.h:160
Definition: clock.h:180
Definition: vid_port.h:42
char * pj_inet_ntop2(int af, const void *src, char *dst, int size)
unsigned clock_rate
Definition: clock.h:194
Definition: format.h:262
Definition: vid_codec.h:148
unsigned w
Definition: types.h:236
pj_status_t pjmedia_avi_player_create_streams(pj_pool_t *pool, const char *filename, unsigned flags, pjmedia_avi_streams **p_streams)
pj_uint32_t s_addr
Definition: vid_codec.h:271
union pjmedia_format::@4 det
pj_bool_t active
Definition: vid_port.h:62
Definition: videodev.h:157
pj_uint32_t id
Definition: format.h:291
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)
pjmedia_port * pjmedia_avi_stream_get_port(pjmedia_avi_stream *stream)
Definition: avi_stream.h:125
pj_status_t pjmedia_transport_media_start(pjmedia_transport *tp, pj_pool_t *tmp_pool, const pjmedia_sdp_session *sdp_local, const pjmedia_sdp_session *sdp_remote, unsigned media_index)
Definition: transport.h:957
Definition: types.h:161
pj_sockaddr_in ipv4
Definition: vid_codec.h:114
Definition: clock.h:184
Definition: videodev.h:134
void pj_shutdown(void)
Definition: frame.h:56
pjmedia_video_format_detail * pjmedia_format_get_video_format_detail(const pjmedia_format *fmt, pj_bool_t assert_valid)
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_clock_create2(pj_pool_t *pool, const pjmedia_clock_param *param, unsigned options, pjmedia_clock_callback *cb, void *user_data, pjmedia_clock **p_clock)
Definition: types.h:63
pjmedia_dir dir
Definition: videodev.h:385
pj_status_t pjmedia_codec_openh264_vid_init(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf)
void * pj_pool_zalloc(pj_pool_t *pool, pj_size_t size)
pj_status_t pjmedia_vid_stream_get_port(pjmedia_vid_stream *stream, pjmedia_dir dir, pjmedia_port **p_port)
unsigned flags
Definition: videodev.h:415
PJ_SUCCESS
struct pjmedia_avi_streams pjmedia_avi_streams
Definition: avi_stream.h:61
pjmedia_format fmt
Definition: videodev.h:420
pjmedia_dir
Definition: types.h:152
pj_status_t pjmedia_vid_port_create(pj_pool_t *pool, const pjmedia_vid_port_param *prm, pjmedia_vid_port **p_vp)
unsigned short pj_uint16_t
pj_status_t pj_init(void)
Definition: types.h:173
pj_status_t pjmedia_endpt_destroy(pjmedia_endpt *endpt)
Definition: endpoint.h:146
struct pjmedia_clock pjmedia_clock
Definition: clock.h:162
Definition: videodev.h:139
size_t pj_size_t
pj_str_t * pj_strset(pj_str_t *str, char *ptr, pj_size_t length)
PJ_FALSE
int pj_rand(void)
#define PJ_UNUSED_ARG(arg)
Definition: format.h:400
pj_status_t pjmedia_codec_ffmpeg_vid_deinit(void)
pjmedia_dir dir
Definition: vid_codec.h:150
void pj_caching_pool_destroy(pj_caching_pool *ch_pool)
#define pj_AF_INET()

 


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