h264-encoder: Fully flush output packets
parent
3ea068b90c
commit
e2e117b02f
|
@ -2,6 +2,7 @@
|
||||||
#include "neatvnc.h"
|
#include "neatvnc.h"
|
||||||
#include "fb.h"
|
#include "fb.h"
|
||||||
#include "sys/queue.h"
|
#include "sys/queue.h"
|
||||||
|
#include "vec.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -60,7 +61,7 @@ struct h264_encoder {
|
||||||
|
|
||||||
struct aml_work* work;
|
struct aml_work* work;
|
||||||
struct nvnc_fb* current_fb;
|
struct nvnc_fb* current_fb;
|
||||||
AVPacket* current_packet;
|
struct vec current_packet;
|
||||||
bool current_frame_is_keyframe;
|
bool current_frame_is_keyframe;
|
||||||
|
|
||||||
bool please_destroy;
|
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);
|
return aml_start(aml_get_default(), self->work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int h264_encoder__encode(struct h264_encoder* self,
|
static int h264_encoder__encode(struct h264_encoder* self, AVFrame* frame_in)
|
||||||
AVFrame* frame_in, AVPacket* packet_out)
|
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -358,13 +358,30 @@ static int h264_encoder__encode(struct h264_encoder* self,
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
goto send_frame_failure;
|
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:
|
send_frame_failure:
|
||||||
av_frame_unref(filtered_frame);
|
av_frame_unref(filtered_frame);
|
||||||
get_frame_failure:
|
get_frame_failure:
|
||||||
av_frame_free(&filtered_frame);
|
av_frame_free(&filtered_frame);
|
||||||
return rc;
|
return rc == AVERROR(EAGAIN) ? 0 : rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void h264_encoder__do_work(void* handle)
|
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;
|
frame->pict_type = AV_PICTURE_TYPE_P;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVPacket* packet = av_packet_alloc();
|
int rc = h264_encoder__encode(self, frame);
|
||||||
assert(packet); // TODO
|
|
||||||
|
|
||||||
int rc = h264_encoder__encode(self, frame, packet);
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
// TODO: log failure
|
// TODO: log failure
|
||||||
av_packet_free(&packet);
|
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->current_packet = packet;
|
|
||||||
|
|
||||||
failure:
|
failure:
|
||||||
av_frame_unref(frame);
|
av_frame_unref(frame);
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
|
@ -410,17 +421,17 @@ static void h264_encoder__on_work_done(void* handle)
|
||||||
self->current_fb = NULL;
|
self->current_fb = NULL;
|
||||||
|
|
||||||
if (self->please_destroy) {
|
if (self->please_destroy) {
|
||||||
av_packet_free(&self->current_packet);
|
vec_destroy(&self->current_packet);
|
||||||
h264_encoder_destroy(self);
|
h264_encoder_destroy(self);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self->current_packet)
|
if (self->current_packet.len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
self->on_packet_ready(self->current_packet->data,
|
self->on_packet_ready(self->current_packet.data,
|
||||||
self->current_packet->size, self->userdata);
|
self->current_packet.len, self->userdata);
|
||||||
av_packet_free(&self->current_packet);
|
vec_clear(&self->current_packet);
|
||||||
|
|
||||||
h264_encoder__schedule_work(self);
|
h264_encoder__schedule_work(self);
|
||||||
}
|
}
|
||||||
|
@ -454,6 +465,9 @@ struct h264_encoder* h264_encoder_create(uint32_t width, uint32_t height,
|
||||||
if (!self)
|
if (!self)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (vec_init(&self->current_packet, 65536) < 0)
|
||||||
|
goto packet_failure;
|
||||||
|
|
||||||
self->work = aml_work_new(h264_encoder__do_work,
|
self->work = aml_work_new(h264_encoder__do_work,
|
||||||
h264_encoder__on_work_done, self, NULL);
|
h264_encoder__on_work_done, self, NULL);
|
||||||
if (!self->work)
|
if (!self->work)
|
||||||
|
@ -515,6 +529,8 @@ hwdevice_ctx_failure:
|
||||||
render_node_failure:
|
render_node_failure:
|
||||||
aml_unref(self->work);
|
aml_unref(self->work);
|
||||||
worker_failure:
|
worker_failure:
|
||||||
|
vec_destroy(&self->current_packet);
|
||||||
|
packet_failure:
|
||||||
free(self);
|
free(self);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue