|
|
@ -21,31 +21,37 @@ |
|
|
|
#include "common/mutex.h" |
|
|
|
#include "common/mutex.h" |
|
|
|
#include "common/swaglog.h" |
|
|
|
#include "common/swaglog.h" |
|
|
|
|
|
|
|
|
|
|
|
#include "encoder.h" |
|
|
|
#include "omx_encoder.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ***** OMX callback functions *****
|
|
|
|
// ***** OMX callback functions *****
|
|
|
|
|
|
|
|
|
|
|
|
static void wait_for_state(EncoderState *s, OMX_STATETYPE state) { |
|
|
|
void OmxEncoder::wait_for_state(OMX_STATETYPE state) { |
|
|
|
pthread_mutex_lock(&s->state_lock); |
|
|
|
pthread_mutex_lock(&this->state_lock); |
|
|
|
while (s->state != state) { |
|
|
|
while (this->state != state) { |
|
|
|
pthread_cond_wait(&s->state_cv, &s->state_lock); |
|
|
|
pthread_cond_wait(&this->state_cv, &this->state_lock); |
|
|
|
} |
|
|
|
} |
|
|
|
pthread_mutex_unlock(&s->state_lock); |
|
|
|
pthread_mutex_unlock(&this->state_lock); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static OMX_ERRORTYPE event_handler(OMX_HANDLETYPE component, OMX_PTR app_data, OMX_EVENTTYPE event, |
|
|
|
static OMX_CALLBACKTYPE omx_callbacks = { |
|
|
|
|
|
|
|
.EventHandler = OmxEncoder::event_handler, |
|
|
|
|
|
|
|
.EmptyBufferDone = OmxEncoder::empty_buffer_done, |
|
|
|
|
|
|
|
.FillBufferDone = OmxEncoder::fill_buffer_done, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OMX_ERRORTYPE OmxEncoder::event_handler(OMX_HANDLETYPE component, OMX_PTR app_data, OMX_EVENTTYPE event, |
|
|
|
OMX_U32 data1, OMX_U32 data2, OMX_PTR event_data) { |
|
|
|
OMX_U32 data1, OMX_U32 data2, OMX_PTR event_data) { |
|
|
|
EncoderState *s = (EncoderState*)app_data; |
|
|
|
OmxEncoder *e = (OmxEncoder*)app_data; |
|
|
|
|
|
|
|
|
|
|
|
switch (event) { |
|
|
|
switch (event) { |
|
|
|
case OMX_EventCmdComplete: |
|
|
|
case OMX_EventCmdComplete: |
|
|
|
assert(data1 == OMX_CommandStateSet); |
|
|
|
assert(data1 == OMX_CommandStateSet); |
|
|
|
LOG("set state event 0x%x", data2); |
|
|
|
LOG("set state event 0x%x", data2); |
|
|
|
pthread_mutex_lock(&s->state_lock); |
|
|
|
pthread_mutex_lock(&e->state_lock); |
|
|
|
s->state = (OMX_STATETYPE)data2; |
|
|
|
e->state = (OMX_STATETYPE)data2; |
|
|
|
pthread_cond_broadcast(&s->state_cv); |
|
|
|
pthread_cond_broadcast(&e->state_cv); |
|
|
|
pthread_mutex_unlock(&s->state_lock); |
|
|
|
pthread_mutex_unlock(&e->state_lock); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case OMX_EventError: |
|
|
|
case OMX_EventError: |
|
|
|
LOGE("OMX error 0x%08x", data1); |
|
|
|
LOGE("OMX error 0x%08x", data1); |
|
|
@ -60,28 +66,22 @@ static OMX_ERRORTYPE event_handler(OMX_HANDLETYPE component, OMX_PTR app_data, O |
|
|
|
return OMX_ErrorNone; |
|
|
|
return OMX_ErrorNone; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static OMX_ERRORTYPE empty_buffer_done(OMX_HANDLETYPE component, OMX_PTR app_data, |
|
|
|
OMX_ERRORTYPE OmxEncoder::empty_buffer_done(OMX_HANDLETYPE component, OMX_PTR app_data, |
|
|
|
OMX_BUFFERHEADERTYPE *buffer) { |
|
|
|
OMX_BUFFERHEADERTYPE *buffer) { |
|
|
|
// printf("empty_buffer_done\n");
|
|
|
|
// printf("empty_buffer_done\n");
|
|
|
|
EncoderState *s = (EncoderState*)app_data; |
|
|
|
OmxEncoder *e = (OmxEncoder*)app_data; |
|
|
|
queue_push(&s->free_in, (void*)buffer); |
|
|
|
queue_push(&e->free_in, (void*)buffer); |
|
|
|
return OMX_ErrorNone; |
|
|
|
return OMX_ErrorNone; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static OMX_ERRORTYPE fill_buffer_done(OMX_HANDLETYPE component, OMX_PTR app_data, |
|
|
|
OMX_ERRORTYPE OmxEncoder::fill_buffer_done(OMX_HANDLETYPE component, OMX_PTR app_data, |
|
|
|
OMX_BUFFERHEADERTYPE *buffer) { |
|
|
|
OMX_BUFFERHEADERTYPE *buffer) { |
|
|
|
// printf("fill_buffer_done\n");
|
|
|
|
// printf("fill_buffer_done\n");
|
|
|
|
EncoderState *s = (EncoderState*)app_data; |
|
|
|
OmxEncoder *e = (OmxEncoder*)app_data; |
|
|
|
queue_push(&s->done_out, (void*)buffer); |
|
|
|
queue_push(&e->done_out, (void*)buffer); |
|
|
|
return OMX_ErrorNone; |
|
|
|
return OMX_ErrorNone; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static OMX_CALLBACKTYPE omx_callbacks = { |
|
|
|
|
|
|
|
.EventHandler = event_handler, |
|
|
|
|
|
|
|
.EmptyBufferDone = empty_buffer_done, |
|
|
|
|
|
|
|
.FillBufferDone = fill_buffer_done, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define PORT_INDEX_IN 0 |
|
|
|
#define PORT_INDEX_IN 0 |
|
|
|
#define PORT_INDEX_OUT 1 |
|
|
|
#define PORT_INDEX_OUT 1 |
|
|
|
|
|
|
|
|
|
|
@ -158,92 +158,77 @@ static const char* omx_color_fomat_name(uint32_t format) { |
|
|
|
|
|
|
|
|
|
|
|
// ***** encoder functions *****
|
|
|
|
// ***** encoder functions *****
|
|
|
|
|
|
|
|
|
|
|
|
void encoder_init(EncoderState *s, const char* filename, int width, int height, int fps, int bitrate, bool h265, bool downscale) { |
|
|
|
OmxEncoder::OmxEncoder(const char* filename, int width, int height, int fps, int bitrate, bool h265, bool downscale) { |
|
|
|
int err; |
|
|
|
int err; |
|
|
|
|
|
|
|
|
|
|
|
memset(s, 0, sizeof(*s)); |
|
|
|
this->filename = filename; |
|
|
|
s->filename = filename; |
|
|
|
this->width = width; |
|
|
|
s->width = width; |
|
|
|
this->height = height; |
|
|
|
s->height = height; |
|
|
|
this->fps = fps; |
|
|
|
s->fps = fps; |
|
|
|
this->remuxing = !h265; |
|
|
|
mutex_init_reentrant(&s->lock); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!h265) { |
|
|
|
|
|
|
|
s->remuxing = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (downscale) { |
|
|
|
|
|
|
|
s->downscale = true; |
|
|
|
|
|
|
|
s->y_ptr2 = (uint8_t *)malloc(s->width*s->height); |
|
|
|
|
|
|
|
s->u_ptr2 = (uint8_t *)malloc(s->width*s->height/4); |
|
|
|
|
|
|
|
s->v_ptr2 = (uint8_t *)malloc(s->width*s->height/4); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
s->segment = -1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
s->state = OMX_StateLoaded; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
s->codec_config = NULL; |
|
|
|
queue_init(&this->free_in); |
|
|
|
|
|
|
|
queue_init(&this->done_out); |
|
|
|
|
|
|
|
|
|
|
|
queue_init(&s->free_in); |
|
|
|
mutex_init_reentrant(&this->lock); |
|
|
|
queue_init(&s->done_out); |
|
|
|
pthread_mutex_init(&this->state_lock, NULL); |
|
|
|
|
|
|
|
pthread_cond_init(&this->state_cv, NULL); |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_init(&s->state_lock, NULL); |
|
|
|
this->downscale = downscale; |
|
|
|
pthread_cond_init(&s->state_cv, NULL); |
|
|
|
if (this->downscale) { |
|
|
|
|
|
|
|
this->y_ptr2 = (uint8_t *)malloc(this->width*this->height); |
|
|
|
if (h265) { |
|
|
|
this->u_ptr2 = (uint8_t *)malloc(this->width*this->height/4); |
|
|
|
err = OMX_GetHandle(&s->handle, (OMX_STRING)"OMX.qcom.video.encoder.hevc", |
|
|
|
this->v_ptr2 = (uint8_t *)malloc(this->width*this->height/4); |
|
|
|
s, &omx_callbacks); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
err = OMX_GetHandle(&s->handle, (OMX_STRING)"OMX.qcom.video.encoder.avc", |
|
|
|
|
|
|
|
s, &omx_callbacks); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto component = (OMX_STRING)(h265 ? "OMX.qcom.video.encoder.hevc" : "OMX.qcom.video.encoder.avc"); |
|
|
|
|
|
|
|
err = OMX_GetHandle(&this->handle, component, this, &omx_callbacks); |
|
|
|
if (err != OMX_ErrorNone) { |
|
|
|
if (err != OMX_ErrorNone) { |
|
|
|
LOGE("error getting codec: %x", err); |
|
|
|
LOGE("error getting codec: %x", err); |
|
|
|
} |
|
|
|
} |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
// printf("handle: %p\n", s->handle);
|
|
|
|
// printf("handle: %p\n", this->handle);
|
|
|
|
|
|
|
|
|
|
|
|
// setup input port
|
|
|
|
// setup input port
|
|
|
|
|
|
|
|
|
|
|
|
OMX_PARAM_PORTDEFINITIONTYPE in_port = {0}; |
|
|
|
OMX_PARAM_PORTDEFINITIONTYPE in_port = {0}; |
|
|
|
in_port.nSize = sizeof(in_port); |
|
|
|
in_port.nSize = sizeof(in_port); |
|
|
|
in_port.nPortIndex = (OMX_U32) PORT_INDEX_IN; |
|
|
|
in_port.nPortIndex = (OMX_U32) PORT_INDEX_IN; |
|
|
|
err = OMX_GetParameter(s->handle, OMX_IndexParamPortDefinition, |
|
|
|
err = OMX_GetParameter(this->handle, OMX_IndexParamPortDefinition, |
|
|
|
(OMX_PTR) &in_port); |
|
|
|
(OMX_PTR) &in_port); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
in_port.format.video.nFrameWidth = s->width; |
|
|
|
in_port.format.video.nFrameWidth = this->width; |
|
|
|
in_port.format.video.nFrameHeight = s->height; |
|
|
|
in_port.format.video.nFrameHeight = this->height; |
|
|
|
in_port.format.video.nStride = VENUS_Y_STRIDE(COLOR_FMT_NV12, s->width); |
|
|
|
in_port.format.video.nStride = VENUS_Y_STRIDE(COLOR_FMT_NV12, this->width); |
|
|
|
in_port.format.video.nSliceHeight = s->height; |
|
|
|
in_port.format.video.nSliceHeight = this->height; |
|
|
|
// in_port.nBufferSize = (s->width * s->height * 3) / 2;
|
|
|
|
// in_port.nBufferSize = (this->width * this->height * 3) / 2;
|
|
|
|
in_port.nBufferSize = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, s->width, s->height); |
|
|
|
in_port.nBufferSize = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, this->width, this->height); |
|
|
|
in_port.format.video.xFramerate = (s->fps * 65536); |
|
|
|
in_port.format.video.xFramerate = (this->fps * 65536); |
|
|
|
in_port.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; |
|
|
|
in_port.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; |
|
|
|
// in_port.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
|
|
|
|
// in_port.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
|
|
|
|
in_port.format.video.eColorFormat = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; |
|
|
|
in_port.format.video.eColorFormat = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_SetParameter(s->handle, OMX_IndexParamPortDefinition, |
|
|
|
err = OMX_SetParameter(this->handle, OMX_IndexParamPortDefinition, |
|
|
|
(OMX_PTR) &in_port); |
|
|
|
(OMX_PTR) &in_port); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err = OMX_GetParameter(s->handle, OMX_IndexParamPortDefinition, |
|
|
|
err = OMX_GetParameter(this->handle, OMX_IndexParamPortDefinition, |
|
|
|
(OMX_PTR) &in_port); |
|
|
|
(OMX_PTR) &in_port); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
s->num_in_bufs = in_port.nBufferCountActual; |
|
|
|
this->num_in_bufs = in_port.nBufferCountActual; |
|
|
|
|
|
|
|
|
|
|
|
// setup output port
|
|
|
|
// setup output port
|
|
|
|
|
|
|
|
|
|
|
|
OMX_PARAM_PORTDEFINITIONTYPE out_port = {0}; |
|
|
|
OMX_PARAM_PORTDEFINITIONTYPE out_port = {0}; |
|
|
|
out_port.nSize = sizeof(out_port); |
|
|
|
out_port.nSize = sizeof(out_port); |
|
|
|
out_port.nPortIndex = (OMX_U32) PORT_INDEX_OUT; |
|
|
|
out_port.nPortIndex = (OMX_U32) PORT_INDEX_OUT; |
|
|
|
err = OMX_GetParameter(s->handle, OMX_IndexParamPortDefinition, |
|
|
|
err = OMX_GetParameter(this->handle, OMX_IndexParamPortDefinition, |
|
|
|
(OMX_PTR)&out_port); |
|
|
|
(OMX_PTR)&out_port); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
out_port.format.video.nFrameWidth = s->width; |
|
|
|
out_port.format.video.nFrameWidth = this->width; |
|
|
|
out_port.format.video.nFrameHeight = s->height; |
|
|
|
out_port.format.video.nFrameHeight = this->height; |
|
|
|
out_port.format.video.xFramerate = 0; |
|
|
|
out_port.format.video.xFramerate = 0; |
|
|
|
out_port.format.video.nBitrate = bitrate; |
|
|
|
out_port.format.video.nBitrate = bitrate; |
|
|
|
if (h265) { |
|
|
|
if (h265) { |
|
|
@ -253,26 +238,26 @@ void encoder_init(EncoderState *s, const char* filename, int width, int height, |
|
|
|
} |
|
|
|
} |
|
|
|
out_port.format.video.eColorFormat = OMX_COLOR_FormatUnused; |
|
|
|
out_port.format.video.eColorFormat = OMX_COLOR_FormatUnused; |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_SetParameter(s->handle, OMX_IndexParamPortDefinition, |
|
|
|
err = OMX_SetParameter(this->handle, OMX_IndexParamPortDefinition, |
|
|
|
(OMX_PTR) &out_port); |
|
|
|
(OMX_PTR) &out_port); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_GetParameter(s->handle, OMX_IndexParamPortDefinition, |
|
|
|
err = OMX_GetParameter(this->handle, OMX_IndexParamPortDefinition, |
|
|
|
(OMX_PTR) &out_port); |
|
|
|
(OMX_PTR) &out_port); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
s->num_out_bufs = out_port.nBufferCountActual; |
|
|
|
this->num_out_bufs = out_port.nBufferCountActual; |
|
|
|
|
|
|
|
|
|
|
|
OMX_VIDEO_PARAM_BITRATETYPE bitrate_type = {0}; |
|
|
|
OMX_VIDEO_PARAM_BITRATETYPE bitrate_type = {0}; |
|
|
|
bitrate_type.nSize = sizeof(bitrate_type); |
|
|
|
bitrate_type.nSize = sizeof(bitrate_type); |
|
|
|
bitrate_type.nPortIndex = (OMX_U32) PORT_INDEX_OUT; |
|
|
|
bitrate_type.nPortIndex = (OMX_U32) PORT_INDEX_OUT; |
|
|
|
err = OMX_GetParameter(s->handle, OMX_IndexParamVideoBitrate, |
|
|
|
err = OMX_GetParameter(this->handle, OMX_IndexParamVideoBitrate, |
|
|
|
(OMX_PTR) &bitrate_type); |
|
|
|
(OMX_PTR) &bitrate_type); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
bitrate_type.eControlRate = OMX_Video_ControlRateVariable; |
|
|
|
bitrate_type.eControlRate = OMX_Video_ControlRateVariable; |
|
|
|
bitrate_type.nTargetBitrate = bitrate; |
|
|
|
bitrate_type.nTargetBitrate = bitrate; |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_SetParameter(s->handle, OMX_IndexParamVideoBitrate, |
|
|
|
err = OMX_SetParameter(this->handle, OMX_IndexParamVideoBitrate, |
|
|
|
(OMX_PTR) &bitrate_type); |
|
|
|
(OMX_PTR) &bitrate_type); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
@ -287,14 +272,14 @@ void encoder_init(EncoderState *s, const char* filename, int width, int height, |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
hevc_type.nSize = sizeof(hevc_type); |
|
|
|
hevc_type.nSize = sizeof(hevc_type); |
|
|
|
hevc_type.nPortIndex = (OMX_U32) PORT_INDEX_OUT; |
|
|
|
hevc_type.nPortIndex = (OMX_U32) PORT_INDEX_OUT; |
|
|
|
err = OMX_GetParameter(s->handle, index_type, |
|
|
|
err = OMX_GetParameter(this->handle, index_type, |
|
|
|
(OMX_PTR) &hevc_type); |
|
|
|
(OMX_PTR) &hevc_type); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
hevc_type.eProfile = OMX_VIDEO_HEVCProfileMain; |
|
|
|
hevc_type.eProfile = OMX_VIDEO_HEVCProfileMain; |
|
|
|
hevc_type.eLevel = OMX_VIDEO_HEVCHighTierLevel5; |
|
|
|
hevc_type.eLevel = OMX_VIDEO_HEVCHighTierLevel5; |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_SetParameter(s->handle, index_type, |
|
|
|
err = OMX_SetParameter(this->handle, index_type, |
|
|
|
(OMX_PTR) &hevc_type); |
|
|
|
(OMX_PTR) &hevc_type); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -302,7 +287,7 @@ void encoder_init(EncoderState *s, const char* filename, int width, int height, |
|
|
|
OMX_VIDEO_PARAM_AVCTYPE avc = { 0 }; |
|
|
|
OMX_VIDEO_PARAM_AVCTYPE avc = { 0 }; |
|
|
|
avc.nSize = sizeof(avc); |
|
|
|
avc.nSize = sizeof(avc); |
|
|
|
avc.nPortIndex = (OMX_U32) PORT_INDEX_OUT; |
|
|
|
avc.nPortIndex = (OMX_U32) PORT_INDEX_OUT; |
|
|
|
err = OMX_GetParameter(s->handle, OMX_IndexParamVideoAvc, &avc); |
|
|
|
err = OMX_GetParameter(this->handle, OMX_IndexParamVideoAvc, &avc); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
avc.nBFrames = 0; |
|
|
|
avc.nBFrames = 0; |
|
|
@ -314,7 +299,7 @@ void encoder_init(EncoderState *s, const char* filename, int width, int height, |
|
|
|
avc.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB; |
|
|
|
avc.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB; |
|
|
|
avc.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable; |
|
|
|
avc.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable; |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_SetParameter(s->handle, OMX_IndexParamVideoAvc, &avc); |
|
|
|
err = OMX_SetParameter(this->handle, OMX_IndexParamVideoAvc, &avc); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -324,7 +309,7 @@ void encoder_init(EncoderState *s, const char* filename, int width, int height, |
|
|
|
// video_port_format.nSize = sizeof(video_port_format);
|
|
|
|
// video_port_format.nSize = sizeof(video_port_format);
|
|
|
|
// video_port_format.nIndex = i;
|
|
|
|
// video_port_format.nIndex = i;
|
|
|
|
// video_port_format.nPortIndex = PORT_INDEX_IN;
|
|
|
|
// video_port_format.nPortIndex = PORT_INDEX_IN;
|
|
|
|
// if (OMX_GetParameter(s->handle, OMX_IndexParamVideoPortFormat, &video_port_format) != OMX_ErrorNone)
|
|
|
|
// if (OMX_GetParameter(this->handle, OMX_IndexParamVideoPortFormat, &video_port_format) != OMX_ErrorNone)
|
|
|
|
// break;
|
|
|
|
// break;
|
|
|
|
// printf("in %d: compression 0x%x format 0x%x %s\n", i,
|
|
|
|
// printf("in %d: compression 0x%x format 0x%x %s\n", i,
|
|
|
|
// video_port_format.eCompressionFormat, video_port_format.eColorFormat,
|
|
|
|
// video_port_format.eCompressionFormat, video_port_format.eColorFormat,
|
|
|
@ -336,83 +321,83 @@ void encoder_init(EncoderState *s, const char* filename, int width, int height, |
|
|
|
// params.nSize = sizeof(params);
|
|
|
|
// params.nSize = sizeof(params);
|
|
|
|
// params.nPortIndex = PORT_INDEX_OUT;
|
|
|
|
// params.nPortIndex = PORT_INDEX_OUT;
|
|
|
|
// params.nProfileIndex = i;
|
|
|
|
// params.nProfileIndex = i;
|
|
|
|
// if (OMX_GetParameter(s->handle, OMX_IndexParamVideoProfileLevelQuerySupported, ¶ms) != OMX_ErrorNone)
|
|
|
|
// if (OMX_GetParameter(this->handle, OMX_IndexParamVideoProfileLevelQuerySupported, ¶ms) != OMX_ErrorNone)
|
|
|
|
// break;
|
|
|
|
// break;
|
|
|
|
// printf("profile %d level 0x%x\n", params.eProfile, params.eLevel);
|
|
|
|
// printf("profile %d level 0x%x\n", params.eProfile, params.eLevel);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
err = OMX_SendCommand(s->handle, OMX_CommandStateSet, OMX_StateIdle, NULL); |
|
|
|
err = OMX_SendCommand(this->handle, OMX_CommandStateSet, OMX_StateIdle, NULL); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
s->in_buf_headers = (OMX_BUFFERHEADERTYPE **)calloc(s->num_in_bufs, sizeof(OMX_BUFFERHEADERTYPE*)); |
|
|
|
this->in_buf_headers = (OMX_BUFFERHEADERTYPE **)calloc(this->num_in_bufs, sizeof(OMX_BUFFERHEADERTYPE*)); |
|
|
|
for (int i=0; i<s->num_in_bufs; i++) { |
|
|
|
for (int i=0; i<this->num_in_bufs; i++) { |
|
|
|
err = OMX_AllocateBuffer(s->handle, &s->in_buf_headers[i], PORT_INDEX_IN, s, |
|
|
|
err = OMX_AllocateBuffer(this->handle, &this->in_buf_headers[i], PORT_INDEX_IN, this, |
|
|
|
in_port.nBufferSize); |
|
|
|
in_port.nBufferSize); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
s->out_buf_headers = (OMX_BUFFERHEADERTYPE **)calloc(s->num_out_bufs, sizeof(OMX_BUFFERHEADERTYPE*)); |
|
|
|
this->out_buf_headers = (OMX_BUFFERHEADERTYPE **)calloc(this->num_out_bufs, sizeof(OMX_BUFFERHEADERTYPE*)); |
|
|
|
for (int i=0; i<s->num_out_bufs; i++) { |
|
|
|
for (int i=0; i<this->num_out_bufs; i++) { |
|
|
|
err = OMX_AllocateBuffer(s->handle, &s->out_buf_headers[i], PORT_INDEX_OUT, s, |
|
|
|
err = OMX_AllocateBuffer(this->handle, &this->out_buf_headers[i], PORT_INDEX_OUT, this, |
|
|
|
out_port.nBufferSize); |
|
|
|
out_port.nBufferSize); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
wait_for_state(s, OMX_StateIdle); |
|
|
|
wait_for_state(OMX_StateIdle); |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_SendCommand(s->handle, OMX_CommandStateSet, OMX_StateExecuting, NULL); |
|
|
|
err = OMX_SendCommand(this->handle, OMX_CommandStateSet, OMX_StateExecuting, NULL); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
wait_for_state(s, OMX_StateExecuting); |
|
|
|
wait_for_state(OMX_StateExecuting); |
|
|
|
|
|
|
|
|
|
|
|
// give omx all the output buffers
|
|
|
|
// give omx all the output buffers
|
|
|
|
for (int i = 0; i < s->num_out_bufs; i++) { |
|
|
|
for (int i = 0; i < this->num_out_bufs; i++) { |
|
|
|
// printf("fill %p\n", s->out_buf_headers[i]);
|
|
|
|
// printf("fill %p\n", this->out_buf_headers[i]);
|
|
|
|
err = OMX_FillThisBuffer(s->handle, s->out_buf_headers[i]); |
|
|
|
err = OMX_FillThisBuffer(this->handle, this->out_buf_headers[i]); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// fill the input free queue
|
|
|
|
// fill the input free queue
|
|
|
|
for (int i = 0; i < s->num_in_bufs; i++) { |
|
|
|
for (int i = 0; i < this->num_in_bufs; i++) { |
|
|
|
queue_push(&s->free_in, (void*)s->in_buf_headers[i]); |
|
|
|
queue_push(&this->free_in, (void*)this->in_buf_headers[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void handle_out_buf(EncoderState *s, OMX_BUFFERHEADERTYPE *out_buf) { |
|
|
|
void OmxEncoder::handle_out_buf(OmxEncoder *e, OMX_BUFFERHEADERTYPE *out_buf) { |
|
|
|
int err; |
|
|
|
int err; |
|
|
|
uint8_t *buf_data = out_buf->pBuffer + out_buf->nOffset; |
|
|
|
uint8_t *buf_data = out_buf->pBuffer + out_buf->nOffset; |
|
|
|
|
|
|
|
|
|
|
|
if (out_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { |
|
|
|
if (out_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { |
|
|
|
if (s->codec_config_len < out_buf->nFilledLen) { |
|
|
|
if (e->codec_config_len < out_buf->nFilledLen) { |
|
|
|
s->codec_config = (uint8_t *)realloc(s->codec_config, out_buf->nFilledLen); |
|
|
|
e->codec_config = (uint8_t *)realloc(e->codec_config, out_buf->nFilledLen); |
|
|
|
} |
|
|
|
} |
|
|
|
s->codec_config_len = out_buf->nFilledLen; |
|
|
|
e->codec_config_len = out_buf->nFilledLen; |
|
|
|
memcpy(s->codec_config, buf_data, out_buf->nFilledLen); |
|
|
|
memcpy(e->codec_config, buf_data, out_buf->nFilledLen); |
|
|
|
#ifdef QCOM2 |
|
|
|
#ifdef QCOM2 |
|
|
|
out_buf->nTimeStamp = 0; |
|
|
|
out_buf->nTimeStamp = 0; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (s->of) { |
|
|
|
if (e->of) { |
|
|
|
//printf("write %d flags 0x%x\n", out_buf->nFilledLen, out_buf->nFlags);
|
|
|
|
//printf("write %d flags 0x%x\n", out_buf->nFilledLen, out_buf->nFlags);
|
|
|
|
fwrite(buf_data, out_buf->nFilledLen, 1, s->of); |
|
|
|
fwrite(buf_data, out_buf->nFilledLen, 1, e->of); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (s->remuxing) { |
|
|
|
if (e->remuxing) { |
|
|
|
if (!s->wrote_codec_config && s->codec_config_len > 0) { |
|
|
|
if (!e->wrote_codec_config && e->codec_config_len > 0) { |
|
|
|
if (s->codec_ctx->extradata_size < s->codec_config_len) { |
|
|
|
if (e->codec_ctx->extradata_size < e->codec_config_len) { |
|
|
|
s->codec_ctx->extradata = (uint8_t *)realloc(s->codec_ctx->extradata, s->codec_config_len + AV_INPUT_BUFFER_PADDING_SIZE); |
|
|
|
e->codec_ctx->extradata = (uint8_t *)realloc(e->codec_ctx->extradata, e->codec_config_len + AV_INPUT_BUFFER_PADDING_SIZE); |
|
|
|
} |
|
|
|
} |
|
|
|
s->codec_ctx->extradata_size = s->codec_config_len; |
|
|
|
e->codec_ctx->extradata_size = e->codec_config_len; |
|
|
|
memcpy(s->codec_ctx->extradata, s->codec_config, s->codec_config_len); |
|
|
|
memcpy(e->codec_ctx->extradata, e->codec_config, e->codec_config_len); |
|
|
|
memset(s->codec_ctx->extradata + s->codec_ctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); |
|
|
|
memset(e->codec_ctx->extradata + e->codec_ctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); |
|
|
|
|
|
|
|
|
|
|
|
err = avcodec_parameters_from_context(s->out_stream->codecpar, s->codec_ctx); |
|
|
|
err = avcodec_parameters_from_context(e->out_stream->codecpar, e->codec_ctx); |
|
|
|
assert(err >= 0); |
|
|
|
assert(err >= 0); |
|
|
|
err = avformat_write_header(s->ofmt_ctx, NULL); |
|
|
|
err = avformat_write_header(e->ofmt_ctx, NULL); |
|
|
|
assert(err >= 0); |
|
|
|
assert(err >= 0); |
|
|
|
|
|
|
|
|
|
|
|
s->wrote_codec_config = true; |
|
|
|
e->wrote_codec_config = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (out_buf->nTimeStamp > 0) { |
|
|
|
if (out_buf->nTimeStamp > 0) { |
|
|
@ -425,14 +410,14 @@ static void handle_out_buf(EncoderState *s, OMX_BUFFERHEADERTYPE *out_buf) { |
|
|
|
pkt.size = out_buf->nFilledLen; |
|
|
|
pkt.size = out_buf->nFilledLen; |
|
|
|
|
|
|
|
|
|
|
|
enum AVRounding rnd = static_cast<enum AVRounding>(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); |
|
|
|
enum AVRounding rnd = static_cast<enum AVRounding>(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); |
|
|
|
pkt.pts = pkt.dts = av_rescale_q_rnd(out_buf->nTimeStamp, in_timebase, s->ofmt_ctx->streams[0]->time_base, rnd); |
|
|
|
pkt.pts = pkt.dts = av_rescale_q_rnd(out_buf->nTimeStamp, in_timebase, e->ofmt_ctx->streams[0]->time_base, rnd); |
|
|
|
pkt.duration = av_rescale_q(50*1000, in_timebase, s->ofmt_ctx->streams[0]->time_base); |
|
|
|
pkt.duration = av_rescale_q(50*1000, in_timebase, e->ofmt_ctx->streams[0]->time_base); |
|
|
|
|
|
|
|
|
|
|
|
if (out_buf->nFlags & OMX_BUFFERFLAG_SYNCFRAME) { |
|
|
|
if (out_buf->nFlags & OMX_BUFFERFLAG_SYNCFRAME) { |
|
|
|
pkt.flags |= AV_PKT_FLAG_KEY; |
|
|
|
pkt.flags |= AV_PKT_FLAG_KEY; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
err = av_write_frame(s->ofmt_ctx, &pkt); |
|
|
|
err = av_write_frame(e->ofmt_ctx, &pkt); |
|
|
|
if (err < 0) { LOGW("ts encoder write issue"); } |
|
|
|
if (err < 0) { LOGW("ts encoder write issue"); } |
|
|
|
|
|
|
|
|
|
|
|
av_free_packet(&pkt); |
|
|
|
av_free_packet(&pkt); |
|
|
@ -445,113 +430,106 @@ static void handle_out_buf(EncoderState *s, OMX_BUFFERHEADERTYPE *out_buf) { |
|
|
|
out_buf->nTimeStamp = 0; |
|
|
|
out_buf->nTimeStamp = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
err = OMX_FillThisBuffer(s->handle, out_buf); |
|
|
|
err = OMX_FillThisBuffer(e->handle, out_buf); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int encoder_encode_frame(EncoderState *s, |
|
|
|
int OmxEncoder::encode_frame(const uint8_t *y_ptr, const uint8_t *u_ptr, const uint8_t *v_ptr, |
|
|
|
const uint8_t *y_ptr, const uint8_t *u_ptr, const uint8_t *v_ptr, |
|
|
|
int in_width, int in_height, |
|
|
|
int in_width, int in_height, |
|
|
|
int *frame_segment, VisionIpcBufExtra *extra) { |
|
|
|
int *frame_segment, VisionIpcBufExtra *extra) { |
|
|
|
|
|
|
|
int err; |
|
|
|
int err; |
|
|
|
pthread_mutex_lock(&s->lock); |
|
|
|
pthread_mutex_lock(&this->lock); |
|
|
|
|
|
|
|
|
|
|
|
if (!s->open) { |
|
|
|
if (!this->is_open) { |
|
|
|
pthread_mutex_unlock(&s->lock); |
|
|
|
pthread_mutex_unlock(&this->lock); |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// this sometimes freezes... put it outside the encoder lock so we can still trigger rotates...
|
|
|
|
// this sometimes freezes... put it outside the encoder lock so we can still trigger rotates...
|
|
|
|
// THIS IS A REALLY BAD IDEA, but apparently the race has to happen 30 times to trigger this
|
|
|
|
// THIS IS A REALLY BAD IDEA, but apparently the race has to happen 30 times to trigger this
|
|
|
|
//pthread_mutex_unlock(&s->lock);
|
|
|
|
//pthread_mutex_unlock(&this->lock);
|
|
|
|
OMX_BUFFERHEADERTYPE* in_buf = (OMX_BUFFERHEADERTYPE *)queue_pop(&s->free_in); |
|
|
|
OMX_BUFFERHEADERTYPE* in_buf = (OMX_BUFFERHEADERTYPE *)queue_pop(&this->free_in); |
|
|
|
//pthread_mutex_lock(&s->lock);
|
|
|
|
//pthread_mutex_lock(&this->lock);
|
|
|
|
|
|
|
|
|
|
|
|
// if (s->rotating) {
|
|
|
|
int ret = this->counter; |
|
|
|
// encoder_close(s);
|
|
|
|
|
|
|
|
// encoder_open(s, s->next_path);
|
|
|
|
|
|
|
|
// s->segment = s->next_segment;
|
|
|
|
|
|
|
|
// s->rotating = false;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
int ret = s->counter; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t *in_buf_ptr = in_buf->pBuffer; |
|
|
|
uint8_t *in_buf_ptr = in_buf->pBuffer; |
|
|
|
// printf("in_buf ptr %p\n", in_buf_ptr);
|
|
|
|
// printf("in_buf ptr %p\n", in_buf_ptr);
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t *in_y_ptr = in_buf_ptr; |
|
|
|
uint8_t *in_y_ptr = in_buf_ptr; |
|
|
|
int in_y_stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, s->width); |
|
|
|
int in_y_stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, this->width); |
|
|
|
int in_uv_stride = VENUS_UV_STRIDE(COLOR_FMT_NV12, s->width); |
|
|
|
int in_uv_stride = VENUS_UV_STRIDE(COLOR_FMT_NV12, this->width); |
|
|
|
// uint8_t *in_uv_ptr = in_buf_ptr + (s->width * s->height);
|
|
|
|
// uint8_t *in_uv_ptr = in_buf_ptr + (this->width * this->height);
|
|
|
|
uint8_t *in_uv_ptr = in_buf_ptr + (in_y_stride * VENUS_Y_SCANLINES(COLOR_FMT_NV12, s->height)); |
|
|
|
uint8_t *in_uv_ptr = in_buf_ptr + (in_y_stride * VENUS_Y_SCANLINES(COLOR_FMT_NV12, this->height)); |
|
|
|
|
|
|
|
|
|
|
|
if (s->downscale) { |
|
|
|
if (this->downscale) { |
|
|
|
I420Scale(y_ptr, in_width, |
|
|
|
I420Scale(y_ptr, in_width, |
|
|
|
u_ptr, in_width/2, |
|
|
|
u_ptr, in_width/2, |
|
|
|
v_ptr, in_width/2, |
|
|
|
v_ptr, in_width/2, |
|
|
|
in_width, in_height, |
|
|
|
in_width, in_height, |
|
|
|
s->y_ptr2, s->width, |
|
|
|
this->y_ptr2, this->width, |
|
|
|
s->u_ptr2, s->width/2, |
|
|
|
this->u_ptr2, this->width/2, |
|
|
|
s->v_ptr2, s->width/2, |
|
|
|
this->v_ptr2, this->width/2, |
|
|
|
s->width, s->height, |
|
|
|
this->width, this->height, |
|
|
|
libyuv::kFilterNone); |
|
|
|
libyuv::kFilterNone); |
|
|
|
y_ptr = s->y_ptr2; |
|
|
|
y_ptr = this->y_ptr2; |
|
|
|
u_ptr = s->u_ptr2; |
|
|
|
u_ptr = this->u_ptr2; |
|
|
|
v_ptr = s->v_ptr2; |
|
|
|
v_ptr = this->v_ptr2; |
|
|
|
} |
|
|
|
} |
|
|
|
err = libyuv::I420ToNV12(y_ptr, s->width, |
|
|
|
err = libyuv::I420ToNV12(y_ptr, this->width, |
|
|
|
u_ptr, s->width/2, |
|
|
|
u_ptr, this->width/2, |
|
|
|
v_ptr, s->width/2, |
|
|
|
v_ptr, this->width/2, |
|
|
|
in_y_ptr, in_y_stride, |
|
|
|
in_y_ptr, in_y_stride, |
|
|
|
in_uv_ptr, in_uv_stride, |
|
|
|
in_uv_ptr, in_uv_stride, |
|
|
|
s->width, s->height); |
|
|
|
this->width, this->height); |
|
|
|
assert(err == 0); |
|
|
|
assert(err == 0); |
|
|
|
|
|
|
|
|
|
|
|
// in_buf->nFilledLen = (s->width*s->height) + (s->width*s->height/2);
|
|
|
|
// in_buf->nFilledLen = (this->width*this->height) + (this->width*this->height/2);
|
|
|
|
in_buf->nFilledLen = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, s->width, s->height); |
|
|
|
in_buf->nFilledLen = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, this->width, this->height); |
|
|
|
in_buf->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; |
|
|
|
in_buf->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; |
|
|
|
in_buf->nOffset = 0; |
|
|
|
in_buf->nOffset = 0; |
|
|
|
in_buf->nTimeStamp = extra->timestamp_eof/1000LL; // OMX_TICKS, in microseconds
|
|
|
|
in_buf->nTimeStamp = extra->timestamp_eof/1000LL; // OMX_TICKS, in microseconds
|
|
|
|
s->last_t = in_buf->nTimeStamp; |
|
|
|
this->last_t = in_buf->nTimeStamp; |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_EmptyThisBuffer(s->handle, in_buf); |
|
|
|
err = OMX_EmptyThisBuffer(this->handle, in_buf); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
// pump output
|
|
|
|
// pump output
|
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
OMX_BUFFERHEADERTYPE *out_buf = (OMX_BUFFERHEADERTYPE *)queue_try_pop(&s->done_out); |
|
|
|
OMX_BUFFERHEADERTYPE *out_buf = (OMX_BUFFERHEADERTYPE *)queue_try_pop(&this->done_out); |
|
|
|
if (!out_buf) { |
|
|
|
if (!out_buf) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
handle_out_buf(s, out_buf); |
|
|
|
handle_out_buf(this, out_buf); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
s->dirty = true; |
|
|
|
this->dirty = true; |
|
|
|
|
|
|
|
|
|
|
|
s->counter++; |
|
|
|
this->counter++; |
|
|
|
|
|
|
|
|
|
|
|
if (frame_segment) { |
|
|
|
if (frame_segment) { |
|
|
|
*frame_segment = s->segment; |
|
|
|
*frame_segment = this->segment; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&s->lock); |
|
|
|
pthread_mutex_unlock(&this->lock); |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void encoder_open(EncoderState *s, const char* path, int segment) { |
|
|
|
void OmxEncoder::encoder_open(const char* path, int segment) { |
|
|
|
int err; |
|
|
|
int err; |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&s->lock); |
|
|
|
pthread_mutex_lock(&this->lock); |
|
|
|
|
|
|
|
|
|
|
|
s->segment = segment; |
|
|
|
this->segment = segment; |
|
|
|
snprintf(s->vid_path, sizeof(s->vid_path), "%s/%s", path, s->filename); |
|
|
|
snprintf(this->vid_path, sizeof(this->vid_path), "%s/%s", path, this->filename); |
|
|
|
LOGD("encoder_open %s remuxing:%d", s->vid_path, s->remuxing); |
|
|
|
LOGD("encoder_open %s remuxing:%d", this->vid_path, this->remuxing); |
|
|
|
|
|
|
|
|
|
|
|
if (s->remuxing) { |
|
|
|
if (this->remuxing) { |
|
|
|
avformat_alloc_output_context2(&s->ofmt_ctx, NULL, NULL, s->vid_path); |
|
|
|
avformat_alloc_output_context2(&this->ofmt_ctx, NULL, NULL, this->vid_path); |
|
|
|
assert(s->ofmt_ctx); |
|
|
|
assert(this->ofmt_ctx); |
|
|
|
|
|
|
|
|
|
|
|
s->out_stream = avformat_new_stream(s->ofmt_ctx, NULL); |
|
|
|
this->out_stream = avformat_new_stream(this->ofmt_ctx, NULL); |
|
|
|
assert(s->out_stream); |
|
|
|
assert(this->out_stream); |
|
|
|
|
|
|
|
|
|
|
|
// set codec correctly
|
|
|
|
// set codec correctly
|
|
|
|
av_register_all(); |
|
|
|
av_register_all(); |
|
|
@ -560,124 +538,124 @@ void encoder_open(EncoderState *s, const char* path, int segment) { |
|
|
|
codec = avcodec_find_encoder(AV_CODEC_ID_H264); |
|
|
|
codec = avcodec_find_encoder(AV_CODEC_ID_H264); |
|
|
|
assert(codec); |
|
|
|
assert(codec); |
|
|
|
|
|
|
|
|
|
|
|
s->codec_ctx = avcodec_alloc_context3(codec); |
|
|
|
this->codec_ctx = avcodec_alloc_context3(codec); |
|
|
|
assert(s->codec_ctx); |
|
|
|
assert(this->codec_ctx); |
|
|
|
s->codec_ctx->width = s->width; |
|
|
|
this->codec_ctx->width = this->width; |
|
|
|
s->codec_ctx->height = s->height; |
|
|
|
this->codec_ctx->height = this->height; |
|
|
|
s->codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; |
|
|
|
this->codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; |
|
|
|
s->codec_ctx->time_base = (AVRational){ 1, s->fps }; |
|
|
|
this->codec_ctx->time_base = (AVRational){ 1, this->fps }; |
|
|
|
|
|
|
|
|
|
|
|
err = avio_open(&s->ofmt_ctx->pb, s->vid_path, AVIO_FLAG_WRITE); |
|
|
|
err = avio_open(&this->ofmt_ctx->pb, this->vid_path, AVIO_FLAG_WRITE); |
|
|
|
assert(err >= 0); |
|
|
|
assert(err >= 0); |
|
|
|
|
|
|
|
|
|
|
|
s->wrote_codec_config = false; |
|
|
|
this->wrote_codec_config = false; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
s->of = fopen(s->vid_path, "wb"); |
|
|
|
this->of = fopen(this->vid_path, "wb"); |
|
|
|
assert(s->of); |
|
|
|
assert(this->of); |
|
|
|
#ifndef QCOM2 |
|
|
|
#ifndef QCOM2 |
|
|
|
if (s->codec_config_len > 0) { |
|
|
|
if (this->codec_config_len > 0) { |
|
|
|
fwrite(s->codec_config, s->codec_config_len, 1, s->of); |
|
|
|
fwrite(this->codec_config, this->codec_config_len, 1, this->of); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// create camera lock file
|
|
|
|
// create camera lock file
|
|
|
|
snprintf(s->lock_path, sizeof(s->lock_path), "%s/%s.lock", path, s->filename); |
|
|
|
snprintf(this->lock_path, sizeof(this->lock_path), "%s/%s.lock", path, this->filename); |
|
|
|
int lock_fd = open(s->lock_path, O_RDWR | O_CREAT, 0777); |
|
|
|
int lock_fd = open(this->lock_path, O_RDWR | O_CREAT, 0777); |
|
|
|
assert(lock_fd >= 0); |
|
|
|
assert(lock_fd >= 0); |
|
|
|
close(lock_fd); |
|
|
|
close(lock_fd); |
|
|
|
|
|
|
|
|
|
|
|
s->open = true; |
|
|
|
this->is_open = true; |
|
|
|
s->counter = 0; |
|
|
|
this->counter = 0; |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&s->lock); |
|
|
|
pthread_mutex_unlock(&this->lock); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void encoder_close(EncoderState *s) { |
|
|
|
void OmxEncoder::encoder_close() { |
|
|
|
int err; |
|
|
|
int err; |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&s->lock); |
|
|
|
pthread_mutex_lock(&this->lock); |
|
|
|
|
|
|
|
|
|
|
|
if (s->open) { |
|
|
|
if (this->is_open) { |
|
|
|
if (s->dirty) { |
|
|
|
if (this->dirty) { |
|
|
|
// drain output only if there could be frames in the encoder
|
|
|
|
// drain output only if there could be frames in the encoder
|
|
|
|
|
|
|
|
|
|
|
|
OMX_BUFFERHEADERTYPE* in_buf = (OMX_BUFFERHEADERTYPE *)queue_pop(&s->free_in); |
|
|
|
OMX_BUFFERHEADERTYPE* in_buf = (OMX_BUFFERHEADERTYPE *)queue_pop(&this->free_in); |
|
|
|
in_buf->nFilledLen = 0; |
|
|
|
in_buf->nFilledLen = 0; |
|
|
|
in_buf->nOffset = 0; |
|
|
|
in_buf->nOffset = 0; |
|
|
|
in_buf->nFlags = OMX_BUFFERFLAG_EOS; |
|
|
|
in_buf->nFlags = OMX_BUFFERFLAG_EOS; |
|
|
|
in_buf->nTimeStamp = s->last_t + 1000000LL/s->fps; |
|
|
|
in_buf->nTimeStamp = this->last_t + 1000000LL/this->fps; |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_EmptyThisBuffer(s->handle, in_buf); |
|
|
|
err = OMX_EmptyThisBuffer(this->handle, in_buf); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
OMX_BUFFERHEADERTYPE *out_buf = (OMX_BUFFERHEADERTYPE *)queue_pop(&s->done_out); |
|
|
|
OMX_BUFFERHEADERTYPE *out_buf = (OMX_BUFFERHEADERTYPE *)queue_pop(&this->done_out); |
|
|
|
|
|
|
|
|
|
|
|
handle_out_buf(s, out_buf); |
|
|
|
handle_out_buf(this, out_buf); |
|
|
|
|
|
|
|
|
|
|
|
if (out_buf->nFlags & OMX_BUFFERFLAG_EOS) { |
|
|
|
if (out_buf->nFlags & OMX_BUFFERFLAG_EOS) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
s->dirty = false; |
|
|
|
this->dirty = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (s->remuxing) { |
|
|
|
if (this->remuxing) { |
|
|
|
av_write_trailer(s->ofmt_ctx); |
|
|
|
av_write_trailer(this->ofmt_ctx); |
|
|
|
avcodec_free_context(&s->codec_ctx); |
|
|
|
avcodec_free_context(&this->codec_ctx); |
|
|
|
avio_closep(&s->ofmt_ctx->pb); |
|
|
|
avio_closep(&this->ofmt_ctx->pb); |
|
|
|
avformat_free_context(s->ofmt_ctx); |
|
|
|
avformat_free_context(this->ofmt_ctx); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
fclose(s->of); |
|
|
|
fclose(this->of); |
|
|
|
} |
|
|
|
} |
|
|
|
unlink(s->lock_path); |
|
|
|
unlink(this->lock_path); |
|
|
|
} |
|
|
|
} |
|
|
|
s->open = false; |
|
|
|
this->is_open = false; |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&s->lock); |
|
|
|
pthread_mutex_unlock(&this->lock); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void encoder_destroy(EncoderState *s) { |
|
|
|
OmxEncoder::~OmxEncoder() { |
|
|
|
int err; |
|
|
|
int err; |
|
|
|
|
|
|
|
|
|
|
|
assert(!s->open); |
|
|
|
assert(!this->is_open); |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_SendCommand(s->handle, OMX_CommandStateSet, OMX_StateIdle, NULL); |
|
|
|
err = OMX_SendCommand(this->handle, OMX_CommandStateSet, OMX_StateIdle, NULL); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
wait_for_state(s, OMX_StateIdle); |
|
|
|
wait_for_state(OMX_StateIdle); |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_SendCommand(s->handle, OMX_CommandStateSet, OMX_StateLoaded, NULL); |
|
|
|
err = OMX_SendCommand(this->handle, OMX_CommandStateSet, OMX_StateLoaded, NULL); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<s->num_in_bufs; i++) { |
|
|
|
for (int i=0; i<this->num_in_bufs; i++) { |
|
|
|
err = OMX_FreeBuffer(s->handle, PORT_INDEX_IN, s->in_buf_headers[i]); |
|
|
|
err = OMX_FreeBuffer(this->handle, PORT_INDEX_IN, this->in_buf_headers[i]); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
} |
|
|
|
} |
|
|
|
free(s->in_buf_headers); |
|
|
|
free(this->in_buf_headers); |
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<s->num_out_bufs; i++) { |
|
|
|
for (int i=0; i<this->num_out_bufs; i++) { |
|
|
|
err = OMX_FreeBuffer(s->handle, PORT_INDEX_OUT, s->out_buf_headers[i]); |
|
|
|
err = OMX_FreeBuffer(this->handle, PORT_INDEX_OUT, this->out_buf_headers[i]); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
} |
|
|
|
} |
|
|
|
free(s->out_buf_headers); |
|
|
|
free(this->out_buf_headers); |
|
|
|
|
|
|
|
|
|
|
|
wait_for_state(s, OMX_StateLoaded); |
|
|
|
wait_for_state(OMX_StateLoaded); |
|
|
|
|
|
|
|
|
|
|
|
err = OMX_FreeHandle(s->handle); |
|
|
|
err = OMX_FreeHandle(this->handle); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
assert(err == OMX_ErrorNone); |
|
|
|
|
|
|
|
|
|
|
|
while (queue_try_pop(&s->free_in));
|
|
|
|
while (queue_try_pop(&this->free_in));
|
|
|
|
while (queue_try_pop(&s->done_out));
|
|
|
|
while (queue_try_pop(&this->done_out));
|
|
|
|
|
|
|
|
|
|
|
|
if (s->codec_config) { |
|
|
|
if (this->codec_config) { |
|
|
|
free(s->codec_config); |
|
|
|
free(this->codec_config); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (s->downscale) { |
|
|
|
if (this->downscale) { |
|
|
|
free(s->y_ptr2); |
|
|
|
free(this->y_ptr2); |
|
|
|
free(s->u_ptr2); |
|
|
|
free(this->u_ptr2); |
|
|
|
free(s->v_ptr2); |
|
|
|
free(this->v_ptr2); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |