static int tee_write_header(AVFormatContext *avf) { TeeContext *tee = avf->priv_data; unsigned nb_slaves = 0, i; const char *filename = avf->filename; char **slaves = NULL; int ret; while (*filename) { char *slave = av_get_token(&filename, slave_delim); if (!slave) { ret = AVERROR(ENOMEM); goto fail; } ret = av_dynarray_add_nofree(&slaves, &nb_slaves, slave); if (ret < 0) { av_free(slave); goto fail; } if (strspn(filename, slave_delim)) filename++; } if (!(tee->slaves = av_mallocz_array(nb_slaves, sizeof(*tee->slaves)))) { ret = AVERROR(ENOMEM); goto fail; } tee->nb_slaves = tee->nb_alive = nb_slaves; for (i = 0; i < nb_slaves; i++) { if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0) { ret = tee_process_slave_failure(avf, i, ret); if (ret < 0) goto fail; } else { log_slave(&tee->slaves[i], avf, AV_LOG_VERBOSE); } av_freep(&slaves[i]); } for (i = 0; i < avf->nb_streams; i++) { int j, mapped = 0; for (j = 0; j < tee->nb_slaves; j++) if (tee->slaves[j].avf) mapped += tee->slaves[j].stream_map[i] >= 0; if (!mapped) av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped " "to any slave.\n", i); } av_free(slaves); return 0; fail: for (i = 0; i < nb_slaves; i++) av_freep(&slaves[i]); close_slaves(avf); av_free(slaves); return ret; }
static int tee_write_header(AVFormatContext *avf) { TeeContext *tee = avf->priv_data; unsigned nb_slaves = 0, i; const char *filename = avf->filename; char *slaves[MAX_SLAVES]; int ret; while (*filename) { if (nb_slaves == MAX_SLAVES) { av_log(avf, AV_LOG_ERROR, "Maximum %d slave muxers reached.\n", MAX_SLAVES); ret = AVERROR_PATCHWELCOME; goto fail; } if (!(slaves[nb_slaves++] = av_get_token(&filename, slave_delim))) { ret = AVERROR(ENOMEM); goto fail; } if (strspn(filename, slave_delim)) filename++; } for (i = 0; i < nb_slaves; i++) { if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0) goto fail; log_slave(&tee->slaves[i], avf, AV_LOG_VERBOSE); av_freep(&slaves[i]); } tee->nb_slaves = nb_slaves; for (i = 0; i < avf->nb_streams; i++) { int j, mapped = 0; for (j = 0; j < tee->nb_slaves; j++) mapped += tee->slaves[j].stream_map[i] >= 0; if (!mapped) av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped " "to any slave.\n", i); } return 0; fail: for (i = 0; i < nb_slaves; i++) av_freep(&slaves[i]); close_slaves(avf); return ret; }
static int tee_write_trailer(AVFormatContext *avf) { TeeContext *tee = avf->priv_data; AVFormatContext *avf2; int ret_all = 0, ret; unsigned i; for (i = 0; i < tee->nb_slaves; i++) { avf2 = tee->slaves[i].avf; if ((ret = av_write_trailer(avf2)) < 0) if (!ret_all) ret_all = ret; if (!(avf2->oformat->flags & AVFMT_NOFILE)) { if ((ret = avio_closep(&avf2->pb)) < 0) if (!ret_all) ret_all = ret; } } close_slaves(avf); return ret_all; }
/** * Handle the received message containing a ‘Client closed’-header * * @return Zero on success -1 on error or interruption, * `errno` will be set accordingly */ static int handle_close_message(void) { /* Servers do not close too often, there is no need to optimise this with another hash table. Doing so would also require some caution because the keys are 32-bit on 32-bit computers, and the client ID:s are 64-bit. */ size_t i, j, ptr = 0, size = 1; size_t *keys = NULL; size_t *old_keys; uint64_t client; hash_entry_t *entry; client_list_t *list; char *command; /* Remove server for all protocols. */ for (i = 0; i < received.header_count; i++) { if (startswith(received.headers[i], "Client closed: ")) { client = parse_client_id(received.headers[i] + strlen("Client closed: ")); foreach_hash_table_entry (reg_table, j, entry) { /* Remove server from list of servers that support the protocol, once, if it is in the list. */ list = (void *)(entry->value); client_list_remove(list, client); if (list->size) continue; /* If no servers support the protocol, list the protocol for removal. */ fail_if (!keys && xmalloc(keys, size, size_t)); fail_if (ptr == size ? growalloc(old_keys, keys, size, size_t) : 0); keys[ptr++] = entry->key; } /* Mark client as closed. */ close_slaves(client); }