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_trailer(AVFormatContext *avf) { TeeContext *tee = avf->priv_data; int ret_all = 0, ret; unsigned i; for (i = 0; i < tee->nb_slaves; i++) { if ((ret = close_slave(&tee->slaves[i])) < 0) { ret = tee_process_slave_failure(avf, i, ret); if (!ret_all && ret < 0) ret_all = ret; } } av_freep(&tee->slaves); return ret_all; }
static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt) { TeeContext *tee = avf->priv_data; AVFormatContext *avf2; AVPacket pkt2; int ret_all = 0, ret; unsigned i, s; int s2; AVRational tb, tb2; for (i = 0; i < tee->nb_slaves; i++) { if (!(avf2 = tee->slaves[i].avf)) continue; s = pkt->stream_index; s2 = tee->slaves[i].stream_map[s]; if (s2 < 0) continue; memset(&pkt2, 0, sizeof(AVPacket)); if ((ret = av_packet_ref(&pkt2, pkt)) < 0) if (!ret_all) { ret_all = ret; continue; } tb = avf ->streams[s ]->time_base; tb2 = avf2->streams[s2]->time_base; pkt2.pts = av_rescale_q(pkt->pts, tb, tb2); pkt2.dts = av_rescale_q(pkt->dts, tb, tb2); pkt2.duration = av_rescale_q(pkt->duration, tb, tb2); pkt2.stream_index = s2; if ((ret = av_apply_bitstream_filters(avf2->streams[s2]->codec, &pkt2, tee->slaves[i].bsfs[s2])) < 0 || (ret = av_interleaved_write_frame(avf2, &pkt2)) < 0) { ret = tee_process_slave_failure(avf, i, ret); if (!ret_all && ret < 0) ret_all = ret; } } return ret_all; }
static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt) { TeeContext *tee = avf->priv_data; AVFormatContext *avf2; AVBSFContext *bsfs; AVPacket pkt2; int ret_all = 0, ret; unsigned i, s; int s2; for (i = 0; i < tee->nb_slaves; i++) { if (!(avf2 = tee->slaves[i].avf)) continue; /* Flush slave if pkt is NULL*/ if (!pkt) { ret = av_interleaved_write_frame(avf2, NULL); if (ret < 0) { ret = tee_process_slave_failure(avf, i, ret); if (!ret_all && ret < 0) ret_all = ret; } continue; } s = pkt->stream_index; s2 = tee->slaves[i].stream_map[s]; if (s2 < 0) continue; memset(&pkt2, 0, sizeof(AVPacket)); if ((ret = av_packet_ref(&pkt2, pkt)) < 0) if (!ret_all) { ret_all = ret; continue; } bsfs = tee->slaves[i].bsfs[s2]; pkt2.stream_index = s2; ret = av_bsf_send_packet(bsfs, &pkt2); if (ret < 0) { av_log(avf, AV_LOG_ERROR, "Error while sending packet to bitstream filter: %s\n", av_err2str(ret)); ret = tee_process_slave_failure(avf, i, ret); if (!ret_all && ret < 0) ret_all = ret; } while(1) { ret = av_bsf_receive_packet(bsfs, &pkt2); if (ret == AVERROR(EAGAIN)) { ret = 0; break; } else if (ret < 0) { break; } av_packet_rescale_ts(&pkt2, bsfs->time_base_out, avf2->streams[s2]->time_base); ret = av_interleaved_write_frame(avf2, &pkt2); if (ret < 0) break; }; if (ret < 0) { ret = tee_process_slave_failure(avf, i, ret); if (!ret_all && ret < 0) ret_all = ret; } } return ret_all; }