Try to create texture from a frame

* NOTE: It doesn't work yet
This commit is contained in:
Malin E
2022-09-16 14:44:39 +02:00
parent c705e5336f
commit e04e06492f
3 changed files with 106 additions and 24 deletions
+9
View File
@@ -177,6 +177,15 @@ if(WIN32)
target_link_libraries(openspace-module-globebrowsing PUBLIC avutil)
add_library(swscale SHARED IMPORTED)
set_target_properties(swscale PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/ext/ffmpeg/lib/swscale-6.dll"
IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/ext/ffmpeg/lib/swscale.lib"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/ext/ffmpeg/include"
)
target_link_libraries(openspace-module-globebrowsing PUBLIC swscale)
else(WIN32)
find_package(FFMPEG REQUIRED)
@@ -89,11 +89,6 @@ FfmpegTileProvider::FfmpegTileProvider(const ghoul::Dictionary& dictionary)
_startTime = p.startTime;
reset();
// Allocate the video frames
_packet = av_packet_alloc();
_avFrame = av_frame_alloc();
_glFrame = av_frame_alloc();
std::string path = absPath(_videoFile).string();
@@ -130,7 +125,7 @@ FfmpegTileProvider::FfmpegTileProvider(const ghoul::Dictionary& dictionary)
LERRORC("FfmpegTileProvider", "Failed to find video stream for " + path);
return;
}
// Find decoder
_decoder = avcodec_find_decoder(_videoStream->codecpar->codec_id);
if (!_decoder) {
@@ -159,9 +154,30 @@ FfmpegTileProvider::FfmpegTileProvider(const ghoul::Dictionary& dictionary)
return;
}
_tileTexture = std::make_unique<ghoul::opengl::Texture>(
ghoul::opengl::Texture(glm::uvec3(_nativeSize, 0), GL_TEXTURE_2D)
);
// Allocate the video frames
_packet = av_packet_alloc();
_avFrame = av_frame_alloc();
_glFrame = av_frame_alloc();
// Fill the destination frame for the convertion
int glFrameSize = av_image_get_buffer_size(
AV_PIX_FMT_RGB24,
_codecContext->width,
_codecContext->height,
1
);
uint8_t* internalBuffer =
reinterpret_cast<uint8_t*>(av_malloc(glFrameSize * sizeof(uint8_t)));
av_image_fill_arrays(
_glFrame->data,
_glFrame->linesize,
internalBuffer,
AV_PIX_FMT_RGB24,
_codecContext->width,
_codecContext->height,
1
);
_lastFrameTime = std::max(Time::convertTime(_startTime), Time::now().j2000Seconds());
}
@@ -181,6 +197,13 @@ TileDepthTransform FfmpegTileProvider::depthTransform() {
void FfmpegTileProvider::update() {
ZoneScoped
if (_tileTexture) {
return;
}
// New frame, new texture make sure it gets reset properly
reset();
// Check if it is time for a new frame
double now = Time::now().j2000Seconds();
double diff = now - _lastFrameTime;
@@ -229,31 +252,73 @@ void FfmpegTileProvider::update() {
return;
}
// Successfully collected a frame
std::cout << "frame: " << _codecContext->frame_number << std::endl;
LINFO(fmt::format(
"Successfully decoded frame {}", _codecContext->frame_number
));
break;
}
// TODO: Get the image data and make it into a ghoul texture and then a tile
/* uint8_t* internalBuffer = new uint8_t[_avFrame->height * _avFrame->width * 3];
for (int y = 0; y < _avFrame->height; y++) {
internalBuffer[y] = *(_avFrame->data[0] + y * _avFrame->linesize[0]);
// TODO: Need to check the format of the video and decide what formats we want to
// support and how they relate to the GL formats
// Convert the color format to AV_PIX_FMT_RGB24
// Only create the conversion context once
if (!_conversionContext) {
_conversionContext = sws_getContext(
_codecContext->width,
_codecContext->height,
_codecContext->pix_fmt,
_codecContext->width,
_codecContext->height,
AV_PIX_FMT_RGB24,
SWS_BICUBIC,
nullptr,
nullptr,
nullptr
);
}
_tileTexture.get()->setPixelData(
reinterpret_cast<char*>(_avFrame->data[0]),
ghoul::opengl::Texture::TakeOwnership::No
// NOTE: This crashes at the moment somewhere inside the sws_scale function
sws_scale(
_conversionContext,
_avFrame->data,
_avFrame->linesize,
0,
_codecContext->height,
_glFrame->data,
_glFrame->linesize
);
// Create the texture
// TODO: We should probably create a deep copy of the data that the Texture object
// can have ownership of, otherwise the destructor crashes and can have other bugs too
_tileTexture = std::make_unique<ghoul::opengl::Texture>(
reinterpret_cast<char*>(_glFrame->data[0]),
glm::uvec3(_nativeSize, 1),
GL_TEXTURE_2D,
ghoul::opengl::Texture::Format::RGB,
GL_RGB
);
if (!_tileTexture) {
throw ghoul::RuntimeError(fmt::format(
"Unable to load texture for frame '{}' in video {}",
_codecContext->frame_number, _videoFile
));
}
// Binds the texture to the tile
_tileTexture->uploadTexture();
_tileTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap);
_tile = Tile{ _tileTexture.get(), std::nullopt, Tile::Status::OK };
*/
// TEST save a grayscale frame into a .pgm file
// This ends up in OpenSpace\build\apps\OpenSpace
// https://github.com/leandromoreira/ffmpeg-libav-tutorial/blob/master/0_hello_world.c
char frame_filename[1024];
/*char frame_filename[1024];
snprintf(frame_filename, sizeof(frame_filename), "%s-%d.pgm", "frame", _codecContext->frame_number);
save_gray_frame(_avFrame->data[0], _avFrame->linesize[0], _avFrame->width, _avFrame->height, frame_filename);
*/
av_packet_unref(_packet);
}
@@ -266,7 +331,13 @@ int FfmpegTileProvider::maxLevel() {
return 1337; // unlimited
}
void FfmpegTileProvider::reset() {}
void FfmpegTileProvider::reset() {
if (_videoFile.empty() || !_tileTexture) {
return;
}
_tileTexture.reset();
}
float FfmpegTileProvider::noDataValueAsFloat() {
@@ -279,7 +350,7 @@ void FfmpegTileProvider::internalInitialize() {
}
FfmpegTileProvider::~FfmpegTileProvider() {
// TODO: Check so internalDeinitialize is called after the last
// TODO: Check so internalDeinitialize is called after the last
// update function and move code there
avformat_close_input(&_formatContext);
av_free(_avFrame);
@@ -289,7 +360,7 @@ FfmpegTileProvider::~FfmpegTileProvider() {
}
void FfmpegTileProvider::internalDeinitialize() {
}
} // namespace openspace::globebrowsing
@@ -34,6 +34,7 @@ extern "C" {
#include <libavcodec/avcodec.h> // avcodec_alloc_context3
#include <libavformat/avformat.h> // avformat_open_input, AVFormatContext
#include <libavutil/imgutils.h> // av_image_get_buffer_size
#include <libswscale/swscale.h> // SwsContext
}
namespace openspace { struct Documentation; }
@@ -42,7 +43,7 @@ namespace openspace::globebrowsing {
class FfmpegTileProvider : public TileProvider {
public:
FfmpegTileProvider(const ghoul::Dictionary& dictionary);
FfmpegTileProvider(const ghoul::Dictionary& dictionary);
~FfmpegTileProvider();
Tile tile(const TileIndex& tileIndex) override final;
@@ -65,6 +66,7 @@ private:
AVFormatContext* _formatContext = nullptr;
AVCodecContext* _codecContext = nullptr;
struct SwsContext* _conversionContext;
const AVCodec* _decoder = nullptr;
AVFrame* _avFrame = nullptr;
AVFrame* _glFrame = nullptr;