int h265_decode(struct viddec_state *vds, struct vidframe *frame, bool marker, uint16_t seq, struct mbuf *mb) { static const uint8_t nal_seq[3] = {0, 0, 1}; int err, ret, got_picture, i; struct h265_nal hdr; AVPacket avpkt; enum vidfmt fmt; if (!vds || !frame || !mb) return EINVAL; err = h265_nal_decode(&hdr, mbuf_buf(mb)); if (err) return err; mbuf_advance(mb, H265_HDR_SIZE); #if 1 debug("h265: decode: %s type=%2d %s\n", h265_is_keyframe(hdr.nal_unit_type) ? "<KEY>" : " ", hdr.nal_unit_type, h265_nalunit_name(hdr.nal_unit_type)); #endif if (vds->frag && hdr.nal_unit_type != H265_NAL_FU) { debug("h265: lost fragments; discarding previous NAL\n"); fragment_rewind(vds); vds->frag = false; } /* handle NAL types */ if (0 <= hdr.nal_unit_type && hdr.nal_unit_type <= 40) { mb->pos -= H265_HDR_SIZE; err = mbuf_write_mem(vds->mb, nal_seq, 3); err |= mbuf_write_mem(vds->mb, mbuf_buf(mb),mbuf_get_left(mb)); if (err) goto out; } else if (H265_NAL_FU == hdr.nal_unit_type) { struct fu fu; err = fu_decode(&fu, mb); if (err) return err; if (fu.s) { if (vds->frag) { debug("h265: lost fragments; ignoring NAL\n"); fragment_rewind(vds); } vds->frag_start = vds->mb->pos; vds->frag = true; hdr.nal_unit_type = fu.type; err = mbuf_write_mem(vds->mb, nal_seq, 3); err = h265_nal_encode_mbuf(vds->mb, &hdr); if (err) goto out; } else { if (!vds->frag) { debug("h265: ignoring fragment\n"); return 0; } if (seq_diff(vds->frag_seq, seq) != 1) { debug("h265: lost fragments detected\n"); fragment_rewind(vds); vds->frag = false; return 0; } } err = mbuf_write_mem(vds->mb, mbuf_buf(mb), mbuf_get_left(mb)); if (err) goto out; if (fu.e) vds->frag = false; vds->frag_seq = seq; } else { warning("h265: unknown NAL type %u\n", hdr.nal_unit_type); return ENOSYS; } if (!marker) { if (vds->mb->end > DECODE_MAXSZ) { warning("h265: decode buffer size exceeded\n"); err = ENOMEM; goto out; } return 0; } if (vds->frag) { err = EPROTO; goto out; } av_init_packet(&avpkt); avpkt.data = vds->mb->buf; avpkt.size = (int)vds->mb->end; ret = avcodec_decode_video2(vds->ctx, vds->pict, &got_picture, &avpkt); if (ret < 0) { debug("h265: decode error\n"); err = EPROTO; goto out; } if (!got_picture) { /* debug("h265: no picture\n"); */ goto out; } switch (vds->pict->format) { case PIX_FMT_YUV420P: fmt = VID_FMT_YUV420P; break; #if 0 case PIX_FMT_YUV444P: fmt = VID_FMT_YUV444; break; #endif default: warning("h265: decode: bad pixel format (%i) (%s)\n", vds->pict->format, av_get_pix_fmt_name(vds->pict->format)); goto out; } for (i=0; i<4; i++) { frame->data[i] = vds->pict->data[i]; frame->linesize[i] = vds->pict->linesize[i]; } frame->size.w = vds->ctx->width; frame->size.h = vds->ctx->height; frame->fmt = fmt; out: mbuf_rewind(vds->mb); vds->frag = false; return err; }
int h265_encode(struct videnc_state *st, bool update, const struct vidframe *frame, videnc_packet_h *pkth, void *arg) { x265_picture *pic_in = NULL, pic_out; x265_nal *nalv; uint32_t i, nalc = 0; int n, err = 0; if (!st || !frame || !pkth || frame->fmt != VID_FMT_YUV420P) return EINVAL; if (!st->x265 || !vidsz_cmp(&st->size, &frame->size)) { err = open_encoder(st, &frame->size); if (err) return err; st->size = frame->size; } if (update) { debug("h265: encode: picture update was requested\n"); } pic_in = x265_picture_alloc(); if (!pic_in) { warning("h265: x265_picture_alloc failed\n"); return ENOMEM; } x265_picture_init(st->param, pic_in); pic_in->sliceType = update ? X265_TYPE_IDR : X265_TYPE_AUTO; pic_in->pts = ++st->pts; /* XXX: add PTS to API */ pic_in->colorSpace = X265_CSP_I420; for (i=0; i<3; i++) { pic_in->planes[i] = frame->data[i]; pic_in->stride[i] = frame->linesize[i]; } /* NOTE: important to get the PTS of the "out" picture */ n = x265_encoder_encode(st->x265, &nalv, &nalc, pic_in, &pic_out); if (n <= 0) goto out; for (i=0; i<nalc; i++) { x265_nal *nal = &nalv[i]; uint8_t *p = nal->payload; size_t len = nal->sizeBytes; bool marker; #if 1 debug("h265: encode: %s type=%2d %s\n", h265_is_keyframe(nal->type) ? "<KEY>" : " ", nal->type, h265_nalunit_name(nal->type)); #endif h265_skip_startcode(&p, &len); /* XXX: use pic_out.pts */ marker = (i+1)==nalc; /* last NAL */ err = packetize(marker, p, len, st->pktsize, pkth, arg); if (err) goto out; } out: if (pic_in) x265_picture_free(pic_in); return err; }