blob: 5578024fc3304dabf5a7508fff559c37bff698dd [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <math.h>
#include <fstream>
#include <iostream>
#include <memory>
#include <lib/media/codec_impl/fourcc.h>
#include <lib/zx/vmar.h>
#include <lib/zx/vmo.h>
#include "raw_frames.h"
size_t AlignUp(size_t raw, size_t alignment) {
return (raw + alignment - 1) / alignment * alignment;
}
// static
std::optional<RawFrames> RawFrames::FromI420File(std::string file,
RawFrames::Layout layout) {
size_t file_size;
std::fstream input_file(file,
std::ios::binary | std::ios::in | std::ios::ate);
if (!input_file.is_open()) {
fprintf(stderr, "Failed to open %s.\n", file.c_str());
return std::nullopt;
}
file_size = input_file.tellg();
input_file.seekg(0);
const size_t source_frame_size = layout.width * layout.height * 3 / 2;
if (file_size % source_frame_size) {
fprintf(stderr, "%s is not raw I420 data of the given dimensions.\n",
file.c_str());
return std::nullopt;
}
const size_t frame_count = file_size / source_frame_size;
if (frame_count == 0) {
fprintf(stderr, "%s has no frames in it.\n", file.c_str());
return std::nullopt;
}
const size_t frame_stored_size =
AlignUp(source_frame_size, layout.frame_alignment);
const size_t total_storage_size = frame_stored_size * frame_count;
zx::vmo vmo;
fzl::VmoMapper mapper;
zx_status_t err = mapper.CreateAndMap(
total_storage_size, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, nullptr, &vmo);
if (err != ZX_OK) {
fprintf(stderr, "Failed to create and map vmo: %d\n", err);
return std::nullopt;
}
// We prepare the image in YV12 format, and add padding for each row if
// `stride` > `width`.
for (size_t i = 0; i < frame_count; ++i) {
char* y_start =
reinterpret_cast<char*>(mapper.start()) + i * frame_stored_size;
char* v_start = y_start + layout.height * layout.stride;
char* u_start = v_start + (layout.height / 2) * (layout.stride / 2);
// Y Plane
for (size_t j = 0; j < layout.height; ++j) {
input_file.read(y_start + j * layout.stride, layout.width);
}
// U Plane
for (size_t j = 0; j < layout.height / 2; ++j) {
input_file.read(u_start + j * (layout.stride / 2), layout.width / 2);
}
// V Plane
for (size_t j = 0; j < layout.height / 2; ++j) {
input_file.read(v_start + j * (layout.stride / 2), layout.width / 2);
}
}
return RawFrames(layout, std::move(vmo), std::move(mapper), frame_stored_size,
frame_count);
}
std::optional<RawFrames::Image> RawFrames::Frame(size_t frame_index) {
if (frame_index >= frame_count_) {
return std::nullopt;
}
zx::vmo vmo;
zx_status_t err = frames_.duplicate(
ZX_RIGHT_READ | ZX_RIGHT_DUPLICATE | ZX_RIGHT_TRANSFER | ZX_RIGHT_MAP,
&vmo);
if (err != ZX_OK) {
fprintf(stderr, "Failed to duplicate frames vmo: %d\n", err);
return std::nullopt;
}
fuchsia::media::VideoUncompressedFormat format = {
.fourcc = make_fourcc('Y', 'V', '1', '2'),
.primary_width_pixels = static_cast<uint32_t>(layout_.width),
.primary_height_pixels = static_cast<uint32_t>(layout_.height),
.secondary_width_pixels = static_cast<uint32_t>(layout_.width / 2),
.secondary_height_pixels = static_cast<uint32_t>(layout_.height / 2),
.planar = true,
.swizzled = false,
.primary_line_stride_bytes = static_cast<uint32_t>(layout_.stride),
.secondary_line_stride_bytes = static_cast<uint32_t>(layout_.stride / 2),
.primary_start_offset = 0,
.secondary_start_offset =
static_cast<uint32_t>(layout_.stride * layout_.height),
.tertiary_start_offset =
static_cast<uint32_t>(layout_.stride * layout_.height +
layout_.stride / 2 * layout_.height / 2),
.primary_display_width_pixels = static_cast<uint32_t>(layout_.width),
.primary_display_height_pixels = static_cast<uint32_t>(layout_.height),
.pixel_aspect_ratio_width = 1,
.pixel_aspect_ratio_height = 1,
};
const size_t offset = frame_index * frame_stored_size_;
return {{
.format = std::move(format),
.image_size = frame_stored_size_,
.vmo_offset = offset,
.vmo = std::move(vmo),
.image_start = reinterpret_cast<uint8_t*>(mapper_.start()) + offset,
}};
}
size_t RawFrames::frame_count() { return frame_count_; }
RawFrames::RawFrames(RawFrames::Layout layout, zx::vmo frames,
fzl::VmoMapper mapper, size_t frame_stored_size,
size_t frame_count)
: layout_(std::move(layout)),
frames_(std::move(frames)),
mapper_(std::move(mapper)),
frame_stored_size_(frame_stored_size),
frame_count_(frame_count) {}