int custom_hdrs_add(struct list *hdrs, const char *name, const char *fmt, ...) { struct pl temp_pl = { NULL, 0 }; struct sip_hdr *hdr; char *value = NULL; va_list ap; int err = 0; va_start(ap, fmt); err = re_vsdprintf(&value, fmt, ap); va_end(ap); hdr = mem_zalloc(sizeof(*hdr), hdr_destructor); if (!hdr || !value) goto error; pl_set_str(&temp_pl, name); err = pl_dup(&hdr->name, &temp_pl); if (err) goto error; pl_set_str(&hdr->val, value); hdr->id = SIP_HDR_NONE; list_append(hdrs, &hdr->le, hdr); return 0; error: mem_deref(hdr); return err; }
static int module_init(void) { struct sa laddr_udp, laddr_http; struct pl addr; uint32_t port; int err; /* UDP bind address */ if (conf_get(restund_conf(), "status_udp_addr", &addr)) pl_set_str(&addr, "127.0.0.1"); if (conf_get_u32(restund_conf(), "status_udp_port", &port)) port = 33000; err = sa_set(&laddr_udp, &addr, port); if (err) { restund_error("status: bad udp bind address: %r:%u", &addr, port); goto out; } /* HTTP bind address */ if (conf_get(restund_conf(), "status_http_addr", &addr)) pl_set_str(&addr, "127.0.0.1"); if (conf_get_u32(restund_conf(), "status_http_port", &port)) port = 8080; err = sa_set(&laddr_http, &addr, port); if (err) { restund_error("status: bad http bind address: %r:%u", &addr, port); goto out; } err = udp_listen(&stg.us, &laddr_udp, udp_recv, NULL); if (err) { restund_warning("status: udp_listen: %m\n", err); goto out; } err = httpd_alloc(&stg.httpd, &laddr_http, httpd_handler); if (err) { restund_warning("status: httpd: %m\n", err); goto out; } stg.start = time(NULL); restund_debug("status: module loaded (udp=%J http=%J)\n", &laddr_udp, &laddr_http); out: if (err) { stg.us = mem_deref(stg.us); stg.httpd = mem_deref(stg.httpd); } return err; }
int module_preload(const char *module) { struct pl path, name; if (!module) return EINVAL; pl_set_str(&path, "."); pl_set_str(&name, module); return load_module(NULL, &path, &name); }
/** * Apply a function handler to certain unknown SIP Headers * * @param msg SIP Message * @param fwd True to traverse forwards, false to traverse backwards * @param name SIP Header name * @param h Function handler * @param arg Handler argument * * @return SIP Header if handler returns true, otherwise NULL */ const struct sip_hdr *sip_msg_xhdr_apply(const struct sip_msg *msg, bool fwd, const char *name, sip_hdr_h *h, void *arg) { struct list *lst; struct le *le; struct pl pl; if (!msg || !name) return NULL; pl_set_str(&pl, name); lst = hash_list(msg->hdrht, hdr_hash(&pl)); le = fwd ? list_head(lst) : list_tail(lst); while (le) { const struct sip_hdr *hdr = le->data; le = fwd ? le->next : le->prev; if (pl_casecmp(&hdr->name, &pl)) continue; if (!h || h(hdr, msg, arg)) return hdr; } return NULL; }
int module_init(const struct conf *conf) { struct pl path; int err; if (!conf) return EINVAL; if (conf_get(conf, "module_path", &path)) pl_set_str(&path, "."); err = conf_apply(conf, "module", module_handler, &path); if (err) return err; err = conf_apply(conf, "module_tmp", module_tmp_handler, &path); if (err) return err; err = conf_apply(conf, "module_app", module_app_handler, &path); if (err) return err; return 0; }
static int normalize_uri(char **out, const char *uri, const struct uri *luri) { struct uri uri2; struct pl pl; int err; if (!out || !uri || !luri) return EINVAL; pl_set_str(&pl, uri); if (0 == uri_decode(&uri2, &pl)) { err = str_dup(out, uri); } else { uri2 = *luri; uri2.user = pl; uri2.password = pl_null; uri2.params = pl_null; err = re_sdprintf(out, "%H", uri_encode, &uri2); } return err; }
/** * Add a contact * * @param contactp Pointer to allocated contact (optional) * @param addr Contact in SIP address format * * @return 0 if success, otherwise errorcode */ int contact_add(struct contact **contactp, const struct pl *addr) { struct contact *c; struct pl pl; int err; c = mem_zalloc(sizeof(*c), destructor); if (!c) return ENOMEM; err = pl_strdup(&c->buf, addr); if (err) goto out; pl_set_str(&pl, c->buf); err = sip_addr_decode(&c->addr, &pl); if (err) { warning("contact: decode error '%r'\n", addr); goto out; } c->status = PRESENCE_UNKNOWN; list_append(&cl, &c->le, c); out: if (err) mem_deref(c); else if (contactp) *contactp = c; return err; }
/** * Apply a function handler to certain unknown HTTP Headers * * @param msg HTTP Message * @param fwd True to traverse forwards, false to traverse backwards * @param name HTTP Header name * @param h Function handler * @param arg Handler argument * * @return HTTP Header if handler returns true, otherwise NULL */ const struct http_hdr *http_msg_xhdr_apply(const struct http_msg *msg, bool fwd, const char *name, http_hdr_h *h, void *arg) { struct le *le; struct pl pl; if (!msg || !name) return NULL; pl_set_str(&pl, name); le = fwd ? msg->hdrl.head : msg->hdrl.tail; while (le) { const struct http_hdr *hdr = le->data; le = fwd ? le->next : le->prev; if (pl_casecmp(&hdr->name, &pl)) continue; if (!h || h(hdr, arg)) return hdr; } return NULL; }
/** * Send SIP instant MESSAGE to a peer * * @param ua User-Agent object * @param peer Peer SIP Address * @param msg Message to send * * @return 0 if success, otherwise errorcode */ int message_send(struct ua *ua, const char *peer, const char *msg) { struct sip_addr addr; struct pl pl; char *uri = NULL; int err = 0; if (!ua || !peer || !msg) return EINVAL; pl_set_str(&pl, peer); err = sip_addr_decode(&addr, &pl); if (err) return err; err = pl_strdup(&uri, &addr.auri); if (err) return err; err = sip_req_send(ua, "MESSAGE", uri, resp_handler, ua, "Accept: text/plain\r\n" "Content-Type: text/plain\r\n" "Content-Length: %zu\r\n" "\r\n%s", str_len(msg), msg); mem_deref(uri); return err; }
void http_header(struct request *request, char* hname, char* val) { enum http_hdr_id id; struct http_hdr *hdr; char *tmp; hdr = mem_zalloc(sizeof(struct http_hdr), hdr_destruct2); re_sdprintf(&tmp, "%s", hname); pl_set_str(&hdr->name, tmp); re_sdprintf(&tmp, "%s", val); pl_set_str(&hdr->val, tmp); id = (enum http_hdr_id)hash_joaat_ci(hdr->name.p, hdr->name.l); id &= 0xFFF; hash_append(request->hdrht, id, &hdr->he, hdr); }
/** * Add a contact * * @param contacts Contacts container * @param contactp Pointer to allocated contact (optional) * @param addr Contact in SIP address format * * @return 0 if success, otherwise errorcode */ int contact_add(struct contacts *contacts, struct contact **contactp, const struct pl *addr) { struct contact *c; struct pl pl; int err; if (!contacts) return EINVAL; c = mem_zalloc(sizeof(*c), destructor); if (!c) return ENOMEM; err = pl_strdup(&c->buf, addr); if (err) goto out; pl_set_str(&pl, c->buf); err = sip_addr_decode(&c->addr, &pl); if (err) { warning("contact: decode error '%r'\n", addr); goto out; } if (0 == msg_param_decode(&c->addr.params, "access", &pl)) { if (0 == pl_strcasecmp(&pl, "block")) { c->access = ACCESS_BLOCK; } else if (0 == pl_strcasecmp(&pl, "allow")) { c->access = ACCESS_ALLOW; } else { warning("contact: unknown 'access=%r' for '%r'\n", &pl, addr); err = EINVAL; goto out; } } else c->access = ACCESS_UNKNOWN; c->status = PRESENCE_UNKNOWN; list_append(&contacts->cl, &c->le, c); hash_append(contacts->cht, hash_joaat_pl(&c->addr.auri), &c->he, c); out: if (err) mem_deref(c); else if (contactp) *contactp = c; return err; }
/** * Send a SIP request with formatted arguments * * @param reqp Pointer to allocated SIP request object * @param sip SIP Stack * @param stateful Stateful client transaction * @param met Null-terminated SIP Method string * @param uri Null-terminated Request URI string * @param route Next hop route URI (optional) * @param auth SIP authentication state * @param sendh Send handler * @param resph Response handler * @param arg Handler argument * @param fmt Formatted SIP headers * * @return 0 if success, otherwise errorcode */ int sip_requestf(struct sip_request **reqp, struct sip *sip, bool stateful, const char *met, const char *uri, const struct uri *route, struct sip_auth *auth, sip_send_h *sendh, sip_resp_h *resph, void *arg, const char *fmt, ...) { struct uri lroute; struct mbuf *mb; va_list ap; int err; if (!sip || !met || !uri || !fmt) return EINVAL; if (!route) { struct pl uripl; pl_set_str(&uripl, uri); err = uri_decode(&lroute, &uripl); if (err) return err; route = &lroute; } mb = mbuf_alloc(2048); if (!mb) return ENOMEM; err = mbuf_write_str(mb, "Max-Forwards: 70\r\n"); if (auth) err |= sip_auth_encode(mb, auth, met, uri); if (err) goto out; va_start(ap, fmt); err = mbuf_vprintf(mb, fmt, ap); va_end(ap); if (err) goto out; mb->pos = 0; err = sip_request(reqp, sip, stateful, met, -1, uri, -1, route, mb, sendh, resph, arg); if (err) goto out; out: mem_deref(mb); return err; }
static int decode_params(struct aucodec_st *st, const char *fmtp) { struct pl params; pl_set_str(¶ms, fmtp); fmt_param_apply(¶ms, decode_param, st); return 0; }
int gst_video1_encoder_set(struct videnc_state **stp, const struct vidcodec *vc, struct videnc_param *prm, const char *fmtp, videnc_packet_h *pkth, void *arg) { struct videnc_state *st = *stp; int err = 0; if (!stp || !vc || !prm || !pkth) return EINVAL; if (!st) { err = allocate_resources(stp); if (err) { warning("gst_video: resource allocation failed\n"); return err; } st = *stp; st->pkth = pkth; st->arg = arg; } else { if (!st->streamer.valid) { warning("gst_video codec: trying to work" " with invalid pipeline\n"); return EINVAL; } if ((st->encoder.bitrate != prm->bitrate || st->encoder.pktsize != prm->pktsize || st->encoder.fps != prm->fps)) { pipeline_close(st); } } st->encoder.bitrate = prm->bitrate; st->encoder.pktsize = prm->pktsize; st->encoder.fps = prm->fps; if (str_isset(fmtp)) { struct pl sdp_fmtp; pl_set_str(&sdp_fmtp, fmtp); /* store new parameters */ fmt_param_apply(&sdp_fmtp, param_handler, st); } info("gst_video: video encoder %s: %d fps, %d bit/s, pktsize=%u\n", vc->name, st->encoder.fps, st->encoder.bitrate, st->encoder.pktsize); return err; }
/** * Load a module by name or by filename * * @param name Module name incl/excl extension, excluding module path * * @return 0 if success, otherwise errorcode * * example: "foo" * example: "foo.so" */ int module_load(const char *name) { char filename[256]; struct pl path, pl_name; int err; if (!str_isset(name)) return EINVAL; append_extension(filename, sizeof(filename), name); pl_set_str(&pl_name, filename); if (conf_get(conf_cur(), "module_path", &path)) pl_set_str(&path, "."); err = load_module(NULL, &path, &pl_name); return err; }
static int encode_update(struct auenc_state **aesp, const struct aucodec *ac, struct auenc_param *prm, const char *fmtp) { struct auenc_state *st; int ret, err = 0; if (!aesp || !ac || !prm) return EINVAL; if (prm->ptime != SPEEX_PTIME) return EPROTO; if (*aesp) return 0; st = mem_zalloc(sizeof(*st), encode_destructor); if (!st) return ENOMEM; st->frame_size = ac->srate * SPEEX_PTIME / 1000; st->channels = ac->ch; /* Encoder */ st->enc = speex_encoder_init(resolve_mode(ac->srate)); if (!st->enc) { err = ENOMEM; goto out; } speex_bits_init(&st->bits); encoder_config(st->enc); ret = speex_encoder_ctl(st->enc, SPEEX_GET_FRAME_SIZE, &st->frame_size); if (ret) { warning("speex: SPEEX_GET_FRAME_SIZE: %d\n", ret); } if (str_isset(fmtp)) { struct pl params; pl_set_str(¶ms, fmtp); fmt_param_apply(¶ms, param_handler, st); } out: if (err) mem_deref(st); else *aesp = st; return err; }
static void add_extension(struct ua *ua, const char *extension) { struct pl e; if (ua->extensionc >= ARRAY_SIZE(ua->extensionv)) { warning("ua: maximum %u number of SIP extensions\n"); return; } pl_set_str(&e, extension); ua->extensionv[ua->extensionc++] = e; }
uint32_t vp8_max_fs(const char *fmtp) { struct pl pl, max_fs; if (!fmtp) return 0; pl_set_str(&pl, fmtp); if (fmt_param_get(&pl, "max-fs", &max_fs)) return pl_u32(&max_fs); return 0; }
static uint32_t packetization_mode(const char *fmtp) { struct pl pl, mode; if (!fmtp) return 0; pl_set_str(&pl, fmtp); if (fmt_param_get(&pl, "packetization-mode", &mode)) return pl_u32(&mode); return 0; }
static bool amr_octet_align(const char *fmtp) { struct pl pl, oa; if (!fmtp) return false; pl_set_str(&pl, fmtp); if (fmt_param_get(&pl, "octet-align", &oa)) return 0 == pl_strcmp(&oa, "1"); return false; }
/** * Send an input string to the UI subsystem * * @param str Input string */ void ui_input_str(const char *str) { struct re_printf pf; struct pl pl; if (!str) return; pf.vph = stdout_handler; pf.arg = NULL; pl_set_str(&pl, str); (void)ui_input_pl(&pf, &pl); }
int gst_video_encode_update(struct videnc_state **vesp, const struct vidcodec *vc, struct videnc_param *prm, const char *fmtp, videnc_packet_h *pkth, void *arg) { struct videnc_state *ves; int err = 0; if (!vesp || !vc || !prm) return EINVAL; ves = *vesp; if (!ves) { ves = mem_zalloc(sizeof(*ves), encode_destructor); if (!ves) return ENOMEM; *vesp = ves; } else { if (ves->gst_inited && (ves->bitrate != prm->bitrate || ves->pktsize != prm->pktsize || ves->fps != prm->fps)) { gst_encoder_close(ves); } } if (str_isset(fmtp)) { struct pl sdp_fmtp; pl_set_str(&sdp_fmtp, fmtp); fmt_param_apply(&sdp_fmtp, param_handler, ves); } ves->bitrate = prm->bitrate; ves->pktsize = prm->pktsize; ves->fps = prm->fps; ves->pkth = pkth; ves->pkth_arg = arg; info("gst_video: video encoder %s: %d fps, %d bit/s, pktsize=%u\n", vc->name, prm->fps, prm->bitrate, prm->pktsize); return err; }
int test_contact(void) { struct contacts *contacts = NULL; struct contact *c; const char *addr = "Neil Young <sip:[email protected]>"; const char *uri = "sip:[email protected]"; struct pl pl_addr; int err; err = contact_init(&contacts); ASSERT_EQ(0, err); /* Verify that we have no contacts */ ASSERT_EQ(0, list_count(contact_list(contacts))); c = contact_find(contacts, "sip:[email protected]"); ASSERT_TRUE(c == NULL); /* Add one contact, list should have one entry and find should return the added contact */ pl_set_str(&pl_addr, addr); err = contact_add(contacts, &c, &pl_addr); ASSERT_EQ(0, err); ASSERT_TRUE(c != NULL); ASSERT_EQ(1, list_count(contact_list(contacts))); c = contact_find(contacts, uri); ASSERT_TRUE(c != NULL); ASSERT_STREQ(addr, contact_str(c)); ASSERT_STREQ(uri, contact_uri(c)); /* Delete 1 contact, verify that list is empty */ mem_deref(c); ASSERT_EQ(0, list_count(contact_list(contacts))); out: mem_deref(contacts); return err; }
/** * Update an existing SIP Dialog from a SIP Message * * @param dlg SIP Dialog to update * @param msg SIP Message * * @return 0 if success, otherwise errorcode */ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) { const struct sip_hdr *contact; struct sip_addr addr; char *uri; int err; if (!dlg || !msg) return EINVAL; contact = sip_msg_hdr(msg, SIP_HDR_CONTACT); if (!contact) return EBADMSG; if (sip_addr_decode(&addr, &contact->val)) return EBADMSG; err = pl_strdup(&uri, &addr.auri); if (err) return err; if (dlg->route.scheme.p == dlg->uri) { struct uri tmp; struct pl pl; pl_set_str(&pl, uri); err = uri_decode(&tmp, &pl); if (err) goto out; dlg->route = tmp; } mem_deref(dlg->uri); dlg->uri = mem_ref(uri); out: mem_deref(uri); return err; }
int location_update(struct list *locl, const struct sip_msg *msg, const struct sip_addr *contact, uint32_t expires) { struct location *loc, *loc_new = NULL; struct loctmp *tmp; struct pl pl; int err; if (!locl || !msg || !contact) return EINVAL; loc = list_ledata(list_apply(locl, true, cmp_handler, (void *)&contact->uri)); if (!loc) { if (expires == 0) return 0; loc = loc_new = mem_zalloc(sizeof(*loc), destructor_location); if (!loc) return ENOMEM; list_append(locl, &loc->le, loc); } else { if (!pl_strcmp(&msg->callid, loc->callid) && msg->cseq.num <= loc->cseq) return EPROTO; if (expires == 0) { loc->rm = true; return 0; } } tmp = mem_zalloc(sizeof(*tmp), destructor_loctmp); if (!tmp) { err = ENOMEM; goto out; } err = pl_strdup(&tmp->uri, &contact->auri); if (err) goto out; pl_set_str(&pl, tmp->uri); if (uri_decode(&tmp->duri, &pl)) { err = EBADMSG; goto out; } err = pl_strdup(&tmp->callid, &msg->callid); if (err) goto out; if (!msg_param_decode(&contact->params, "q", &pl)) tmp->q = pl_float(&pl); else tmp->q = 1; tmp->cseq = msg->cseq.num; tmp->expires = expires; tmp->src = msg->src; out: if (err) { mem_deref(loc_new); mem_deref(tmp); } else { mem_deref(loc->tmp); loc->tmp = tmp; } return err; }
int stun_uri_decode(struct stun_uri *stun_uri, const char *str) { struct uri uri; struct pl pl_uri; uint16_t port; struct pl transp; int err; if (!stun_uri || !str) return EINVAL; pl_set_str(&pl_uri, str); err = uri_decode(&uri, &pl_uri); if (err) { warning("cannot decode URI (%r)\n", &pl_uri); return err; } if (0 == pl_strcasecmp(&uri.scheme, "stun") || 0 == pl_strcasecmp(&uri.scheme, "stuns")) { stun_uri->scheme = STUN_SCHEME_STUN; } else if (0 == pl_strcasecmp(&uri.scheme, "turn") || 0 == pl_strcasecmp(&uri.scheme, "turns")) { stun_uri->scheme = STUN_SCHEME_TURN; } else { warning("unsupported stun scheme (%r)\n", &uri.scheme); return ENOTSUP; } stun_uri->secure = 's' == tolower(uri.scheme.p[uri.scheme.l-1]); if (uri.port) port = uri.port; else if (stun_uri->secure) port = 5349; else port = 3478; err = sa_set(&stun_uri->addr, &uri.host, port); if (err) { warning("invalid stun address (%r)\n", &uri.host); return err; } if (0 == re_regex(str, strlen(str), "?transport=[a-z]+", &transp)) { if (0 == pl_strcasecmp(&transp, "udp")) stun_uri->proto = IPPROTO_UDP; else if (0 == pl_strcasecmp(&transp, "tcp")) stun_uri->proto = IPPROTO_TCP; else { warning("unsupported stun transport (%r)\n", &transp); return ENOTSUP; } } else { stun_uri->proto = IPPROTO_UDP; } return 0; }
static void call_event_handler(struct call *call, enum call_event ev, const char *str, void *arg) { struct ua *ua = arg; const char *peeruri; struct call *call2 = NULL; int err; MAGIC_CHECK(ua); peeruri = call_peeruri(call); /* stop any ringtones */ ua->play = mem_deref(ua->play); switch (ev) { case CALL_EVENT_INCOMING: if (contact_block_access(peeruri)) { info("ua: blocked access: \"%s\"\n", peeruri); ua_event(ua, UA_EVENT_CALL_CLOSED, call, str); mem_deref(call); break; } switch (ua->acc->answermode) { case ANSWERMODE_EARLY: (void)call_progress(call); break; case ANSWERMODE_AUTO: (void)call_answer(call, 200); break; case ANSWERMODE_MANUAL: default: if (list_count(&ua->calls) > 1) { (void)play_file(&ua->play, "callwaiting.wav", 3); } else { /* Alert user */ (void)play_file(&ua->play, "ring.wav", -1); } ua_event(ua, UA_EVENT_CALL_INCOMING, call, peeruri); break; } break; case CALL_EVENT_RINGING: (void)play_file(&ua->play, "ringback.wav", -1); ua_event(ua, UA_EVENT_CALL_RINGING, call, peeruri); break; case CALL_EVENT_PROGRESS: ua_printf(ua, "Call in-progress: %s\n", peeruri); ua_event(ua, UA_EVENT_CALL_PROGRESS, call, peeruri); break; case CALL_EVENT_ESTABLISHED: ua_printf(ua, "Call established: %s\n", peeruri); ua_event(ua, UA_EVENT_CALL_ESTABLISHED, call, peeruri); break; case CALL_EVENT_CLOSED: if (call_scode(call)) { const char *tone; tone = translate_errorcode(call_scode(call)); if (tone) (void)play_file(&ua->play, tone, 1); } ua_event(ua, UA_EVENT_CALL_CLOSED, call, str); mem_deref(call); break; case CALL_EVENT_TRANSFER: /* * Create a new call to transfer target. * * NOTE: we will automatically connect a new call to the * transfer target */ ua_printf(ua, "transferring call to %s\n", str); err = ua_call_alloc(&call2, ua, VIDMODE_ON, NULL, call, call_localuri(call)); if (!err) { struct pl pl; pl_set_str(&pl, str); err = call_connect(call2, &pl); if (err) { warning("ua: transfer: connect error: %m\n", err); } } if (err) { (void)call_notify_sipfrag(call, 500, "Call Error"); mem_deref(call2); } break; case CALL_EVENT_TRANSFER_FAILED: ua_event(ua, UA_EVENT_CALL_TRANSFER_FAILED, call, str); break; } }
static int cmd_contact(struct re_printf *pf, void *arg) { const struct cmd_arg *carg = arg; struct contacts *contacts = baresip_contacts(); struct contact *cnt = NULL; struct pl dname, user, pl; struct le *le; int err = 0; pl_set_str(&pl, carg->prm); dname.l = user.l = pl.l; err |= re_hprintf(pf, "\n"); for (le = list_head(contact_list(contacts)); le; le = le->next) { struct contact *c = le->data; dname.p = contact_addr(c)->dname.p; user.p = contact_addr(c)->uri.user.p; /* if displayname is set, try to match the displayname * otherwise we try to match the username only */ if (dname.p) { if (0 == pl_casecmp(&dname, &pl)) { err |= re_hprintf(pf, "%s\n", contact_str(c)); cnt = c; } } else if (user.p) { if (0 == pl_casecmp(&user, &pl)) { err |= re_hprintf(pf, "%s\n", contact_str(c)); cnt = c; } } } if (!cnt) err |= re_hprintf(pf, "(no matches)\n"); if (carg->complete && cnt) { switch (carg->key) { case '|': err = ua_connect(uag_current(), NULL, NULL, contact_str(cnt), NULL, VIDMODE_ON); if (err) { warning("contact: ua_connect failed: %m\n", err); } break; case '=': chat_peer = contact_str(cnt); (void)re_hprintf(pf, "Selected chat peer: %s\n", chat_peer); re_snprintf(cmd_desc, sizeof(cmd_desc), "Send MESSAGE to %s", chat_peer); break; default: break; } } return err; }
static int alloc(struct vidcodec_st **stp, struct vidcodec *vc, const char *name, struct vidcodec_prm *encp, const char *fmtp, vidcodec_enq_h *enqh, vidcodec_send_h *sendh, void *arg) { struct vidcodec_st *st; int err = 0; if (!encp) return EINVAL; st = mem_zalloc(sizeof(*st), destructor); if (!st) return ENOMEM; st->vc = mem_ref(vc); st->encprm = *encp; if (0 == str_casecmp(name, "H263")) st->codec_id = CODEC_ID_H263; else if (0 == str_casecmp(name, "H264")) st->codec_id = CODEC_ID_H264; else if (0 == str_casecmp(name, "MP4V-ES")) st->codec_id = CODEC_ID_MPEG4; else { err = EINVAL; goto out; } st->enc.mb = mbuf_alloc(FF_MIN_BUFFER_SIZE * 20); st->dec.mb = mbuf_alloc(1024); st->mb_frag = mbuf_alloc(1024); if (!st->enc.mb || !st->dec.mb || !st->mb_frag) { err = ENOMEM; goto out; } st->enc.sz_max = st->enc.mb->size; st->dec.sz_max = st->dec.mb->size; if (st->codec_id == CODEC_ID_H264) { #ifndef USE_X264 err = init_encoder(st); #endif } else err = init_encoder(st); if (err) { DEBUG_WARNING("%s: could not init encoder\n", name); goto out; } err = init_decoder(st); if (err) { DEBUG_WARNING("%s: could not init decoder\n", name); goto out; } if (str_isset(fmtp)) { struct pl sdp_fmtp; pl_set_str(&sdp_fmtp, fmtp); fmt_param_apply(&sdp_fmtp, param_handler, st); } st->enqh = enqh; st->sendh = sendh; st->arg = arg; re_printf("video codec %s: %d fps, %d bit/s\n", name, encp->fps, encp->bitrate); out: if (err) mem_deref(st); else *stp = st; return err; }
int encode_update(struct videnc_state **vesp, const struct vidcodec *vc, struct videnc_param *prm, const char *fmtp, videnc_packet_h *pkth, void *arg) { struct videnc_state *st; int err = 0; if (!vesp || !vc || !prm || !pkth) return EINVAL; if (*vesp) return 0; st = mem_zalloc(sizeof(*st), destructor); if (!st) return ENOMEM; st->encprm = *prm; st->pkth = pkth; st->arg = arg; st->codec_id = avcodec_resolve_codecid(vc->name); if (st->codec_id == AV_CODEC_ID_NONE) { err = EINVAL; goto out; } st->mb = mbuf_alloc(FF_MIN_BUFFER_SIZE * 20); st->mb_frag = mbuf_alloc(1024); if (!st->mb || !st->mb_frag) { err = ENOMEM; goto out; } st->sz_max = st->mb->size; if (st->codec_id == AV_CODEC_ID_H264) { #ifndef USE_X264 err = init_encoder(st); #endif } else err = init_encoder(st); if (err) { warning("avcodec: %s: could not init encoder\n", vc->name); goto out; } if (str_isset(fmtp)) { struct pl sdp_fmtp; pl_set_str(&sdp_fmtp, fmtp); fmt_param_apply(&sdp_fmtp, param_handler, st); } debug("avcodec: video encoder %s: %d fps, %d bit/s, pktsize=%u\n", vc->name, prm->fps, prm->bitrate, prm->pktsize); out: if (err) mem_deref(st); else *vesp = st; return err; }