shithub: rtmp

ref: edfe7779751000c6f9f2f6a805668309f33ef314
dir: /main.c/

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <bio.h>
#include "adts.h"
#include "ivf.h"
#include "rtmp.h"
#include "util.h"

int mainstacksize = 65536;
int debug = 0;

static RTMP *r;
static ulong sid;
static uvlong ns₀;
static uvlong vms;

static void
usage(void)
{
	fprint(2, "usage: %s [-a AUDIO] URL\n", argv0);
	threadexitsall("usage");
}

static uvlong
ns2ms(uvlong z, uvlong ns)
{
	if(z != 0 && z != Zns₀)
		ns = z - ns₀ + ns;

	return ns / 1000000ULL;
}

static void
audio(void *aux)
{
	ADTSFrame af;
	Biobuf *a;
	u64int ms;

	a = aux;
	memset(&af, 0, sizeof(af));
	af.ns₀ = Zns₀;
	for(;;){
		if(adtsread(a, &af) != 0)
			goto err;
		if(af.sz == 0) /* eof */
			break;
		ms = ns2ms(af.ns₀, af.ns);

		if(rtmpdata(r, sid, ms, Taudio, af.buf, af.sz) != 0){
err:
			fprint(2, "%r\n");
			break;
		}

		/* protect against overruns */
		if(vms+200 < ms)
			sleep(100);
	}

	/* FIXME properly close RTMP connection */

	threadexitsall(nil);
}

void
threadmain(int argc, char **argv)
{
	Biobuf *a, v;
	IVFrame vf;
	u64int ms;
	IVF ivf;

	a = nil;
	ARGBEGIN{
	case 'd':
		debug++;
		break;
	case 'a':
		if((a = Bopen(EARGF(usage()), OREAD)) == nil)
			sysfatal("%r");
		break;
	default:
		usage();
	}ARGEND

	if(argc != 1)
		usage();
	if(Binit(&v, 0, OREAD) != 0 || ivfopen(&v, &ivf) != 0)
		sysfatal("%r");
	if(strcmp(ivf.type, "AVC1") != 0)
		sysfatal("not H.264");

	ns₀ = nsec() - 10ULL*1000000000ULL; /* base, -10s */
	srand(time(nil));
	if((r = rtmpdial(argv[0])) == nil)
		sysfatal("%r");

	if(rtmpstream(r, &sid) != 0 ||
	   rtmppublish(r, sid, PubLive, nil) != 0 ||
	   rtmpmeta(r, sid, VcodecH264, ivf.w, ivf.h, a != nil ? AcodecAAC : -1) != 0){
		sysfatal("%r");
	}

	if(a != nil)
		proccreate(audio, a, mainstacksize);

	memset(&vf, 0, sizeof(vf));
	for(;;){
		if(ivfread(&ivf, &vf) != 0)
			sysfatal("%r");
		if(vf.sz == 0)
			break;
		ms = ns2ms(ivf.ns₀, vf.ns);
		if(rtmpdata(r, sid, ms, Tvideo, vf.buf, vf.sz) != 0){
			fprint(2, "%r\n");
			break;
		}
		vms = ms;
	}

	/* FIXME properly close RTMP connection */

	threadexitsall(nil);
}