h264-encoder: Fully flush output packets

pull/63/head
Andri Yngvason 2022-04-10 16:21:28 +00:00
parent 3ea068b90c
commit e2e117b02f
1 changed files with 33 additions and 17 deletions

View File

@ -2,6 +2,7 @@
#include "neatvnc.h"
#include "fb.h"
#include "sys/queue.h"
#include "vec.h"
#include <stdlib.h>
#include <stdint.h>
@ -60,7 +61,7 @@ struct h264_encoder {
struct aml_work* work;
struct nvnc_fb* current_fb;
AVPacket* current_packet;
struct vec current_packet;
bool current_frame_is_keyframe;
bool please_destroy;
@ -336,8 +337,7 @@ static int h264_encoder__schedule_work(struct h264_encoder* self)
return aml_start(aml_get_default(), self->work);
}
static int h264_encoder__encode(struct h264_encoder* self,
AVFrame* frame_in, AVPacket* packet_out)
static int h264_encoder__encode(struct h264_encoder* self, AVFrame* frame_in)
{
int rc;
@ -358,13 +358,30 @@ static int h264_encoder__encode(struct h264_encoder* self,
if (rc != 0)
goto send_frame_failure;
rc = avcodec_receive_packet(self->codec_ctx, packet_out);
AVPacket* packet = av_packet_alloc();
assert(packet); // TODO
while (1) {
rc = avcodec_receive_packet(self->codec_ctx, packet);
if (rc != 0)
break;
vec_append(&self->current_packet, packet->data, packet->size);
packet->stream_index = 0;
av_packet_unref(packet);
}
// Frame should always start with a zero:
assert(self->current_packet.len == 0 ||
((char*)self->current_packet.data)[0] == 0);
av_packet_free(&packet);
send_frame_failure:
av_frame_unref(filtered_frame);
get_frame_failure:
av_frame_free(&filtered_frame);
return rc;
return rc == AVERROR(EAGAIN) ? 0 : rc;
}
static void h264_encoder__do_work(void* handle)
@ -384,18 +401,12 @@ static void h264_encoder__do_work(void* handle)
frame->pict_type = AV_PICTURE_TYPE_P;
}
AVPacket* packet = av_packet_alloc();
assert(packet); // TODO
int rc = h264_encoder__encode(self, frame, packet);
int rc = h264_encoder__encode(self, frame);
if (rc != 0) {
// TODO: log failure
av_packet_free(&packet);
goto failure;
}
self->current_packet = packet;
failure:
av_frame_unref(frame);
av_frame_free(&frame);
@ -410,17 +421,17 @@ static void h264_encoder__on_work_done(void* handle)
self->current_fb = NULL;
if (self->please_destroy) {
av_packet_free(&self->current_packet);
vec_destroy(&self->current_packet);
h264_encoder_destroy(self);
return;
}
if (!self->current_packet)
if (self->current_packet.len == 0)
return;
self->on_packet_ready(self->current_packet->data,
self->current_packet->size, self->userdata);
av_packet_free(&self->current_packet);
self->on_packet_ready(self->current_packet.data,
self->current_packet.len, self->userdata);
vec_clear(&self->current_packet);
h264_encoder__schedule_work(self);
}
@ -454,6 +465,9 @@ struct h264_encoder* h264_encoder_create(uint32_t width, uint32_t height,
if (!self)
return NULL;
if (vec_init(&self->current_packet, 65536) < 0)
goto packet_failure;
self->work = aml_work_new(h264_encoder__do_work,
h264_encoder__on_work_done, self, NULL);
if (!self->work)
@ -515,6 +529,8 @@ hwdevice_ctx_failure:
render_node_failure:
aml_unref(self->work);
worker_failure:
vec_destroy(&self->current_packet);
packet_failure:
free(self);
return NULL;
}