#include <vpx_codec.h>#include <vpx_decoder.h>#include <vpx_image.h>#include <vp8dx.h>#include "frame.h"#include "stream.h"#include "decoder.h"#include "misc.h" #pragma lib "../libvpx/libvpx.$M.a" typedef struct Aux Aux; struct Aux { vpx_codec_ctx_t ctx;}; static voiddecode(void *x){ uvlong lasttimestamp; Decoder *d; Channel *c; Frame *f; Streamframe sf; Aux *a; int res; u8int *pic; vpx_codec_iter_t iter; uvlong start; vpx_image_t *im; threadsetname("decoder/vpx"); d = x; a = d->aux; lasttimestamp = 0; memset(&pic, 0, sizeof(pic)); for(res = 0; res >= 0 && (res = Sread(d->s, &sf)) == 0 && sf.sz > 0;){ start = nanosec(); if((res = vpx_codec_decode(&a->ctx, sf.buf, sf.sz, NULL, 0)) != 0){ werrstr("vpx_codec_decode failed: %s", vpx_codec_error_detail(&a->ctx)); break; } d->decodetime = nanosec() - start; for(iter = nil;;){ if((im = vpx_codec_get_frame(&a->ctx, &iter)) == nil) break; if(im->fmt != VPX_IMG_FMT_I420){ vpx_img_free(im); werrstr("images other than YUV420 aren't supported"); res = -1; break; } if((f = newframe(im->d_w, im->d_h, im->planes, im->stride[0], im->stride[1])) != nil){ f->crop.left = 0; f->crop.top = 0; f->crop.right = im->d_w; f->crop.bottom = im->d_h; f->dt = (sf.timestamp - lasttimestamp) * d->timebase * 1000000000ULL; lasttimestamp = sf.timestamp; vpx_img_free(im); if(sendp(d->frames, f) < 0){ free(f); goto done; } } } } if(res != 0) fprint(2, "vpx: %r\n"); done: vpx_codec_destroy(&a->ctx); free(a); c = d->finished; sendp(c, res == 0 ? nil : "error"); chanclose(c); threadexits(nil);} static intvpxopen(Decoder *d){ Aux *a; vpx_codec_iface_t *iface; vpx_codec_dec_cfg_t cfg = {nproc, 0, 0}; a = calloc(1, sizeof(*a)); iface = d->s->fmt == FmtVP9 ? vpx_codec_vp9_dx() : vpx_codec_vp8_dx(); if(vpx_codec_dec_init_ver(&a->ctx, iface, &cfg, 0, VPX_DECODER_ABI_VERSION) != 0){ werrstr("vpx_codec_dec_init failed"); free(a); return -1; } d->aux = a; proccreate(decode, d, 65536); return 0;} static voidvpxclose(Decoder *d){ USED(d);} Decoderops vpxops = { .open = vpxopen, .close = vpxclose,};
#include <vpx_codec.h>
#include <vpx_decoder.h>
#include <vpx_image.h>
#include <vp8dx.h>
#include "frame.h"
#include "stream.h"
#include "decoder.h"
#include "misc.h"
#pragma lib "../libvpx/libvpx.$M.a"
typedef struct Aux Aux;
struct Aux {
vpx_codec_ctx_t ctx;
};
static void
decode(void *x)
{
uvlong lasttimestamp;
Decoder *d;
Channel *c;
Frame *f;
Streamframe sf;
Aux *a;
int res;
u8int *pic;
vpx_codec_iter_t iter;
uvlong start;
vpx_image_t *im;
threadsetname("decoder/vpx");
d = x;
a = d->aux;
lasttimestamp = 0;
memset(&pic, 0, sizeof(pic));
for(res = 0; res >= 0 && (res = Sread(d->s, &sf)) == 0 && sf.sz > 0;){
start = nanosec();
if((res = vpx_codec_decode(&a->ctx, sf.buf, sf.sz, NULL, 0)) != 0){
werrstr("vpx_codec_decode failed: %s", vpx_codec_error_detail(&a->ctx));
break;
}
d->decodetime = nanosec() - start;
for(iter = nil;;){
if((im = vpx_codec_get_frame(&a->ctx, &iter)) == nil)
break;
if(im->fmt != VPX_IMG_FMT_I420){
vpx_img_free(im);
werrstr("images other than YUV420 aren't supported");
res = -1;
break;
}
if((f = newframe(im->d_w, im->d_h, im->planes, im->stride[0], im->stride[1])) != nil){
f->crop.left = 0;
f->crop.top = 0;
f->crop.right = im->d_w;
f->crop.bottom = im->d_h;
f->dt = (sf.timestamp - lasttimestamp) * d->timebase * 1000000000ULL;
lasttimestamp = sf.timestamp;
vpx_img_free(im);
if(sendp(d->frames, f) < 0){
free(f);
goto done;
}
}
}
}
if(res != 0)
fprint(2, "vpx: %r\n");
done:
vpx_codec_destroy(&a->ctx);
free(a);
c = d->finished;
sendp(c, res == 0 ? nil : "error");
chanclose(c);
threadexits(nil);
}
static int
vpxopen(Decoder *d)
{
Aux *a;
vpx_codec_iface_t *iface;
vpx_codec_dec_cfg_t cfg = {nproc, 0, 0};
a = calloc(1, sizeof(*a));
iface = d->s->fmt == FmtVP9 ? vpx_codec_vp9_dx() : vpx_codec_vp8_dx();
if(vpx_codec_dec_init_ver(&a->ctx, iface, &cfg, 0, VPX_DECODER_ABI_VERSION) != 0){
werrstr("vpx_codec_dec_init failed");
free(a);
return -1;
}
d->aux = a;
proccreate(decode, d, 65536);
return 0;
}
static void
vpxclose(Decoder *d)
{
USED(d);
}
Decoderops vpxops = {
.open = vpxopen,
.close = vpxclose,
};