message, message->buffer->index, message->buffer);
break;
case HAL_CODEC_MESSAGE_TYPE_RESOLUTION_CHANGED:
+ message->resolution.width = ((hal_codec_resolution_s *)value)->width;
+ message->resolution.height = ((hal_codec_resolution_s *)value)->height;
+ LOGI("ResolutionChanged[%dx%d]", message->resolution.width, message->resolution.height);
break;
case HAL_CODEC_MESSAGE_TYPE_ERROR:
message->error_code = GPOINTER_TO_INT(value);
}
+static int __codec_v4l2_subscribe_event(int device_fd, uint32_t event, uint32_t input_id)
+{
+ struct v4l2_event_subscription subscription = {.type = event, .id = input_id, };
+
+ LOGI("subscribe event[%u], input_id[%u]", subscription.type, subscription.id);
+
+ if (ioctl(device_fd, VIDIOC_SUBSCRIBE_EVENT, &subscription) < 0) {
+ LOGW("failed[%s]", __codec_v4l2_get_error_string(errno));
+ return HAL_CODEC_ERROR_INTERNAL;
+ }
+
+ return HAL_CODEC_ERROR_NONE;
+}
+
+
static int __codec_v4l2_set_config(codec_hal_buffer_control_s *buffer_control,
enum v4l2_buf_type buf_type, enum v4l2_memory memory,
hal_codec_format_e format, int width, int height, int max_width, int max_height)
LOGI("start");
- /* stream off */
- for (i = 0 ; i < CODEC_HAL_BUFFER_CONTROL_TYPE_MAX ; i++) {
- ret = __codec_v4l2_stream(handle->device_fd,
- handle->buffer_control[i].config.buf_type, FALSE);
- if (ret != HAL_CODEC_ERROR_NONE) {
- LOGE("buffer_control[%d] STREAMOFF failed[0x%x]", i, ret);
- return ret;
- }
- }
-
- /* wait for output buffer */
+ /* output */
buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT];
+ ret = __codec_v4l2_stream(handle->device_fd,
+ buffer_control->config.buf_type, FALSE);
+ if (ret != HAL_CODEC_ERROR_NONE) {
+ LOGE("[OUTPUT] STREAMOFF failed[0x%x]", ret);
+ return ret;
+ }
+
g_mutex_lock(&buffer_control->lock);
while (buffer_control->buffers.queued_count < buffer_control->buffers.count) {
g_mutex_unlock(&buffer_control->lock);
/* release output buffer */
- buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT];
buffers = &buffer_control->buffers;
for (i = 0 ; i < buffers->count ; i++) {
return ret;
}
- /* release input buffer */
+ /* input */
buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT];
buffers = &buffer_control->buffers;
+ ret = __codec_v4l2_stream(handle->device_fd,
+ buffer_control->config.buf_type, FALSE);
+ if (ret != HAL_CODEC_ERROR_NONE) {
+ LOGE("[INPUT] STREAMOFF failed[0x%x]", ret);
+ return ret;
+ }
+
for (i = 0 ; i < buffers->count ; i++) {
codec_buffer = &buffers->buffer[i];
int i = 0;
int ret = 0;
int device_fd = CODEC_HAL_INITIAL_FD;
+ uint32_t input_id = 0;
hal_codec_resolution_s in_max_resolution = {0, 0};
hal_codec_resolution_s out_max_resolution = {0, 0};
char *node_path = NULL;
return HAL_CODEC_ERROR_DEVICE_OPEN;
}
+ /* subscribe SOURCE_CHANGE event */
+ if (ioctl(device_fd, VIDIOC_G_INPUT, &input_id) < 0)
+ LOGW("G_INPUT failed, use default input id[%d]", input_id);
+
+ if (__codec_v4l2_subscribe_event(device_fd, V4L2_EVENT_SOURCE_CHANGE, input_id) != HAL_CODEC_ERROR_NONE) {
+ LOGW("subscribe event[SOURCE_CHANGE] failed");
+ return HAL_CODEC_ERROR_DEVICE_READ;
+ }
+
/* set format for input */
ret = __codec_v4l2_set_config(&handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT],
in_buf_type, V4L2_MEMORY_MMAP, in_format, width, height, in_max_resolution.width, in_max_resolution.height);
}
+static void __codec_v4l2_restart_output_stream(codec_hal_handle_s *handle)
+{
+ int i = 0;
+ int k = 0;
+ int ret = 0;
+ int new_width = 0;
+ int new_height = 0;
+ gint64 end_time = 0;
+ struct v4l2_format v4l2_fmt;
+ hal_codec_memory_s *codec_memory = NULL;
+ hal_codec_buffer_s *codec_buffer = NULL;
+ codec_hal_buffer_control_s *buffer_control = NULL;
+ codec_hal_buffers_s *buffers = NULL;
+
+ if (!handle) {
+ LOGE("NULL handle");
+ return;
+ }
+
+ LOGI("start");
+
+ buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT];
+
+ ret = __codec_v4l2_stream(handle->device_fd,
+ buffer_control->config.buf_type, FALSE);
+ if (ret != HAL_CODEC_ERROR_NONE) {
+ LOGE("[OUTPUT] STREAMOFF failed[0x%x]", ret);
+ return;
+ }
+
+ g_mutex_lock(&buffer_control->lock);
+
+ while (buffer_control->buffers.queued_count < buffer_control->buffers.count) {
+ LOGW("wait for output buffer[queued:%d vs count:%u]",
+ buffer_control->buffers.queued_count, buffer_control->buffers.count);
+
+ end_time = g_get_monotonic_time() + G_TIME_SPAN_SECOND;
+
+ if (!g_cond_wait_until(&buffer_control->cond, &buffer_control->lock, end_time)) {
+ LOGE("timeout: wait for output buffer");
+ break;
+ }
+
+ LOGW("signal received, check it again[queued:%d,count:%u]",
+ buffer_control->buffers.queued_count, buffer_control->buffers.count);
+ }
+
+ g_mutex_unlock(&buffer_control->lock);
+
+ /* release output buffer */
+ buffers = &buffer_control->buffers;
+
+ for (i = 0 ; i < buffers->count ; i++) {
+ codec_buffer = &buffers->buffer[i];
+ codec_memory = &codec_buffer->memory;
+
+ for (k = 0 ; k < codec_memory->num_fd ; k++) {
+ if (codec_memory->fd[k] > CODEC_HAL_INITIAL_FD) {
+ LOGI("[OUTPUT][%d][%d] close fd[%d]", i, k, codec_memory->fd[k]);
+ close(codec_memory->fd[k]);
+ codec_memory->fd[k] = CODEC_HAL_INITIAL_FD;
+ }
+
+ if (buffers->bo[i][k]) {
+ LOGI("[OUTPUT][%d][%d] unref bo[%p]", i, k, buffers->bo[i][k]);
+ tbm_bo_unref(buffers->bo[i][k]);
+ buffers->bo[i][k] = NULL;
+ }
+ }
+ }
+
+ ret = __codec_v4l2_reqbufs(handle->device_fd,
+ buffer_control->config.buf_type, V4L2_MEMORY_MMAP, 0, NULL);
+ if (ret != HAL_CODEC_ERROR_NONE) {
+ LOGE("[OUTPUT] REQBUFS 0 failed[0x%x]", ret);
+ return;
+ }
+
+ memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format));
+
+ v4l2_fmt.type = buffer_control->config.buf_type;
+
+ if (ioctl(handle->device_fd, VIDIOC_G_FMT, &v4l2_fmt) < 0) {
+ LOGE("G_FMT failed");
+ return;
+ }
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(buffer_control->config.buf_type)) {
+ new_width = v4l2_fmt.fmt.pix_mp.width;
+ new_height = v4l2_fmt.fmt.pix_mp.height;
+ } else {
+ new_width = v4l2_fmt.fmt.pix.width;
+ new_height = v4l2_fmt.fmt.pix.height;
+ }
+
+ LOGI("new resolution[%dx%d]", new_width, new_height);
+
+ buffer_control->config.resolution.width = new_width;
+ buffer_control->config.resolution.height = new_height;
+
+ ret = __codec_v4l2_start_stream(handle, buffer_control, BUFFER_NUM_OUTPUT);
+ if (ret != HAL_CODEC_ERROR_NONE) {
+ LOGE("[output] __codec_start_stream failed[0x%x]", ret);
+ return;
+ }
+
+ __codec_v4l2_message_send(handle, HAL_CODEC_MESSAGE_TYPE_RESOLUTION_CHANGED,
+ &buffer_control->config.resolution);
+
+ LOGI("done");
+}
+
+
static gpointer __codec_v4l2_buffer_handler_func(gpointer data)
{
int ret = 0;
if (ret < 0)
break;
+ if (revents & POLLPRI) {
+ struct v4l2_event event = { 0, };
+
+ if (ioctl(handle->device_fd, VIDIOC_DQEVENT, &event) == 0) {
+ if (event.type == V4L2_EVENT_SOURCE_CHANGE) {
+ LOGW("SOURCE_CHANGE event detected, restart stream with new resolution");
+ __codec_v4l2_restart_output_stream(handle);
+ } else {
+ LOGW("Unknown event[%u]", event.type);
+ }
+ } else {
+ LOGI("VIDIOC_DQEVENT failed");
+ }
+ }
+
if (revents & POLLERR) {
LOGE("POLLERR[errno:%d,%s]", poll_errno, __codec_v4l2_get_error_string(poll_errno));
ret = __codec_v4l2_qbuf(handle->device_fd,
buffer_control, idle_buffer);
-
if (ret != HAL_CODEC_ERROR_NONE) {
LOGE("QBUF[%p] failed[i:%d], 0x%x",
buffer, idle_buffer->index, ret);