live_forward.c 3.13 KB
Newer Older
Julian Rother's avatar
Julian Rother committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

#include "util.h"

int main(int argc, char *argv[])
{
	int i, err, canceled;
	int *idxmap;
	char *src, *dest;
	AVFormatContext *demux, *mux;
	AVPacket pkt;
	AVStream *stream;
	AVDictionary *muxopts;
	if (argc != 5)
		return 1;
	av_register_all();
	avformat_network_init();
	init_env();
	init_avlogbuf();
	memset(&pkt, 0, sizeof(pkt));
	av_init_packet(&pkt);

	jobid = atoi(argv[1]);
	src = jstr(jlookup(argv[4], "src"), "rtmp://example.com:99999/notfound");
	dest = jstr(jlookup(argv[4], "dest"), "rtmp://example.com:99999/notfound");
	ping_job(jobid, "running", 0);

	demux = 0;
	if (err = avformat_open_input(&demux, src, 0, 0))
		job_failed("Opening input stream failed: %s", av_err2str(err));
	avformat_find_stream_info(demux, 0);
	err = avformat_alloc_output_context2(&mux,
			av_guess_format(jstr(jlookup(argv[4], "format"), 0), dest, 0), 0, dest);
	if (err < 0)
		job_failed("Error allocating muxer context: %s", av_err2str(err));
	av_dict_copy(&mux->metadata, demux->metadata, 0);
	parse_dict(&mux->metadata, jlookup(argv[4], "metadata"));
	idxmap = malloc(sizeof(int)*demux->nb_streams);
	for (i = 0; i < demux->nb_streams; i ++)
	{
		idxmap[i] = -1;
		if (demux->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO
				&& demux->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO
				&& demux->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
			continue;
		stream = avformat_new_stream(mux, 0);
		av_dict_copy(&stream->metadata, mux->streams[i]->metadata, 0);
		idxmap[i] = stream->index;
		avcodec_parameters_copy(mux->streams[i]->codecpar,
				demux->streams[i]->codecpar);
		mux->streams[i]->codecpar->codec_tag = 0;
		mux->streams[i]->time_base = demux->streams[i]->time_base;
	}
Julian Rother's avatar
Julian Rother committed
55
	avio_open(&mux->pb, dest, AVIO_FLAG_WRITE);
Julian Rother's avatar
Julian Rother committed
56 57 58 59 60 61 62 63
	muxopts = 0;
	parse_dict(&muxopts, jlookup(argv[4], "options"));
	if ((err = avformat_write_header(mux, &muxopts)) < 0)
		job_failed("Writing header failed: %s", av_err2str(err));
	canceled = 0;
	while (!canceled && !av_read_frame(demux, &pkt))
	{
		if (!checktime(30))
Julian Rother's avatar
Julian Rother committed
64
			canceled = ping_job(jobid, "running", "{\"log\": \"%s\"}", jescape(get_avlogbuf()));
Julian Rother's avatar
Julian Rother committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
		if (pkt.stream_index >= demux->nb_streams
				|| idxmap[pkt.stream_index] == -1)
			continue;
		pkt.stream_index = idxmap[pkt.stream_index];
		pkt.pts = av_rescale_q_rnd(pkt.pts, demux->streams[pkt.stream_index]->time_base,
				mux->streams[pkt.stream_index]->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
		pkt.dts = av_rescale_q_rnd(pkt.dts, demux->streams[pkt.stream_index]->time_base,
				mux->streams[pkt.stream_index]->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
		pkt.duration = av_rescale_q(pkt.duration, demux->streams[pkt.stream_index]->time_base,
				mux->streams[pkt.stream_index]->time_base);
		pkt.pos = -1;
		if (err = av_interleaved_write_frame(mux, &pkt))
			job_failed("Could not write frame: %s", av_err2str(err));
	}
	avformat_close_input(&demux);
	av_interleaved_write_frame(mux, 0);
	if (err = av_write_trailer(mux))
		job_failed("Error writing trailer", av_err2str(err));
Julian Rother's avatar
Julian Rother committed
83
	avio_closep(&mux->pb);
Julian Rother's avatar
Julian Rother committed
84
	ping_job(jobid, "finished", "{\"log\": \"%s\"}", jescape(get_avlogbuf()));
Julian Rother's avatar
Julian Rother committed
85 86
	return 0;
}