CI-Build 2022-08-07
This commit is contained in:
commit
31271676b3
5 changed files with 207 additions and 2 deletions
69
automation/v4-docs/get-frame.txt
Normal file
69
automation/v4-docs/get-frame.txt
Normal file
|
@ -0,0 +1,69 @@
|
|||
Video Frame functions in Automation 4
|
||||
|
||||
This file describes the interface used for reading frames from loaded videos.
|
||||
|
||||
---
|
||||
|
||||
Get a specific frame from the currently loaded video on which multiple other
|
||||
functions are defined.
|
||||
|
||||
function aegisub.get_frame(frame_number, withSubtitles)
|
||||
|
||||
@frame_number (number)
|
||||
Number of frame to retrieve.
|
||||
|
||||
@withSubtitles (boolean)
|
||||
Optional. Whether to load with subtitles drawn on to the frame.
|
||||
|
||||
Returns: frame (userdata)
|
||||
The frame object defines multiple other functions. See below.
|
||||
|
||||
---
|
||||
|
||||
Get width of frame object.
|
||||
|
||||
function frame:width()
|
||||
|
||||
Returns: number
|
||||
Width in pixels.
|
||||
|
||||
---
|
||||
|
||||
Get height of frame object.
|
||||
|
||||
function frame:height()
|
||||
|
||||
Returns: number
|
||||
Height in pixels.
|
||||
|
||||
---
|
||||
|
||||
Get RGB pixel value at a certain position of frame object.
|
||||
|
||||
function frame:frame:getPixel(x, y)
|
||||
|
||||
@x (number)
|
||||
Pixel to retrieve on the x-axis
|
||||
|
||||
@y (number)
|
||||
Pixel to retrieve on the y-axis
|
||||
|
||||
Returns: number
|
||||
Integer value representing the RGB pixel value.
|
||||
|
||||
---
|
||||
|
||||
Get ASS formated pixel value at a certain position of frame object.
|
||||
|
||||
function frame:getPixelFormatted(x, y)
|
||||
|
||||
@x (number)
|
||||
Pixel to retrieve on the x-axis
|
||||
|
||||
@y (number)
|
||||
Pixel to retrieve on the y-axis
|
||||
|
||||
Returns: string
|
||||
String in ASS format representing the pixel value. e.g. "&H0073FF&"
|
||||
|
||||
---
|
|
@ -55,3 +55,12 @@ Returns: 0 values
|
|||
|
||||
---
|
||||
|
||||
Determining whether there are unsaved changes
|
||||
|
||||
function aegisub.gui.is_modified()
|
||||
|
||||
Returns: 1 boolean
|
||||
1. Whether the current file has unsaved changes.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -50,8 +50,9 @@
|
|||
#include "project.h"
|
||||
#include "selection_controller.h"
|
||||
#include "subs_controller.h"
|
||||
#include "video_controller.h"
|
||||
#include "text_selection_controller.h"
|
||||
#include "video_controller.h"
|
||||
#include "video_frame.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <libaegisub/dispatch.h>
|
||||
|
@ -200,6 +201,116 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<VideoFrame> check_VideoFrame(lua_State *L) {
|
||||
auto framePtr = static_cast<std::shared_ptr<VideoFrame>*>(luaL_checkudata(L, 1, "VideoFrame"));
|
||||
return *framePtr;
|
||||
}
|
||||
|
||||
int FrameWidth(lua_State *L) {
|
||||
std::shared_ptr<VideoFrame> frame = check_VideoFrame(L);
|
||||
push_value(L, frame->width);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FrameHeight(lua_State *L) {
|
||||
std::shared_ptr<VideoFrame> frame = check_VideoFrame(L);
|
||||
push_value(L, frame->height);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FramePixel(lua_State *L) {
|
||||
std::shared_ptr<VideoFrame> frame = check_VideoFrame(L);
|
||||
size_t x = lua_tointeger(L, -2);
|
||||
size_t y = lua_tointeger(L, -1);
|
||||
lua_pop(L, 2);
|
||||
|
||||
if (x < frame->width && y < frame->height) {
|
||||
if (frame->flipped)
|
||||
y = frame->height - y;
|
||||
|
||||
size_t pos = y * frame->pitch + x * 4;
|
||||
// VideoFrame is stored as BGRA, but we want to return RGB
|
||||
int pixelValue = frame->data[pos+2] * 65536 + frame->data[pos+1] * 256 + frame->data[pos];
|
||||
push_value(L, pixelValue);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FramePixelFormatted(lua_State *L) {
|
||||
std::shared_ptr<VideoFrame> frame = check_VideoFrame(L);
|
||||
size_t x = lua_tointeger(L, -2);
|
||||
size_t y = lua_tointeger(L, -1);
|
||||
lua_pop(L, 2);
|
||||
|
||||
if (x < frame->width && y < frame->height) {
|
||||
if (frame->flipped)
|
||||
y = frame->height - y;
|
||||
|
||||
size_t pos = y * frame->pitch + x * 4;
|
||||
// VideoFrame is stored as BGRA, Color expects RGBA
|
||||
agi::Color* color = new agi::Color(frame->data[pos+2], frame->data[pos+1], frame->data[pos], frame->data[pos+3]);
|
||||
push_value(L, color->GetAssOverrideFormatted());
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FrameDestory(lua_State *L) {
|
||||
std::shared_ptr<VideoFrame> frame = check_VideoFrame(L);
|
||||
frame.~shared_ptr<VideoFrame>();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_frame(lua_State *L)
|
||||
{
|
||||
// get frame number from stack
|
||||
const agi::Context *c = get_context(L);
|
||||
int frameNumber = lua_tointeger(L, 1);
|
||||
|
||||
bool withSubtitles = false;
|
||||
if (lua_gettop(L) >= 2) {
|
||||
withSubtitles = lua_toboolean(L, 2);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
static const struct luaL_Reg FrameTableDefinition [] = {
|
||||
{"width", FrameWidth},
|
||||
{"height", FrameHeight},
|
||||
{"getPixel", FramePixel},
|
||||
{"getPixelFormatted", FramePixelFormatted},
|
||||
{"__gc", FrameDestory},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
// create and register metatable if not already done
|
||||
if (luaL_newmetatable(L, "VideoFrame")) {
|
||||
// metatable.__index = metatable
|
||||
lua_pushstring(L, "__index");
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, -3);
|
||||
|
||||
luaL_register(L, NULL, FrameTableDefinition);
|
||||
}
|
||||
|
||||
if (c && c->project->Timecodes().IsLoaded()) {
|
||||
std::shared_ptr<VideoFrame> frame = c->videoController->GetFrame(frameNumber, !withSubtitles);
|
||||
|
||||
void *userData = lua_newuserdata(L, sizeof(std::shared_ptr<VideoFrame>));
|
||||
|
||||
new(userData) std::shared_ptr<VideoFrame>(frame);
|
||||
|
||||
luaL_getmetatable(L, "VideoFrame");
|
||||
lua_setmetatable(L, -2);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_keyframes(lua_State *L)
|
||||
{
|
||||
if (const agi::Context *c = get_context(L))
|
||||
|
@ -319,6 +430,12 @@ namespace {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int lua_is_modified(lua_State *L)
|
||||
{
|
||||
push_value(L, get_context(L)->subsController->IsModified());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int project_properties(lua_State *L)
|
||||
{
|
||||
const agi::Context *c = get_context(L);
|
||||
|
@ -523,11 +640,13 @@ namespace {
|
|||
set_field<project_properties>(L, "project_properties");
|
||||
set_field<lua_get_audio_selection>(L, "get_audio_selection");
|
||||
set_field<lua_set_status_text>(L, "set_status_text");
|
||||
lua_createtable(L, 0, 4);
|
||||
set_field<get_frame>(L, "get_frame");
|
||||
lua_createtable(L, 0, 5);
|
||||
set_field<lua_get_text_cursor>(L, "get_cursor");
|
||||
set_field<lua_set_text_cursor>(L, "set_cursor");
|
||||
set_field<lua_get_text_selection>(L, "get_selection");
|
||||
set_field<lua_set_text_selection>(L, "set_selection");
|
||||
set_field<lua_is_modified>(L, "is_modified");
|
||||
lua_setfield(L, -2, "gui");
|
||||
|
||||
// store aegisub table to globals
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "time_range.h"
|
||||
#include "async_video_provider.h"
|
||||
#include "utils.h"
|
||||
#include "video_frame.h"
|
||||
|
||||
#include <libaegisub/ass/time.h>
|
||||
|
||||
|
@ -222,6 +223,11 @@ int VideoController::FrameAtTime(int time, agi::vfr::Time type) const {
|
|||
return context->project->Timecodes().FrameAtTime(time, type);
|
||||
}
|
||||
|
||||
std::shared_ptr<VideoFrame> VideoController::GetFrame(int frame, bool raw) const {
|
||||
double timestamp = TimeAtFrame(frame, agi::vfr::EXACT);
|
||||
return provider->GetFrame(frame, timestamp, raw);
|
||||
}
|
||||
|
||||
void VideoController::OnVideoError(VideoProviderErrorEvent const& err) {
|
||||
wxLogError(
|
||||
"Failed seeking video. The video file may be corrupt or incomplete.\n"
|
||||
|
|
|
@ -39,6 +39,7 @@ class AssDialogue;
|
|||
class AsyncVideoProvider;
|
||||
struct SubtitlesProviderErrorEvent;
|
||||
struct VideoProviderErrorEvent;
|
||||
struct VideoFrame;
|
||||
|
||||
namespace agi {
|
||||
struct Context;
|
||||
|
@ -159,4 +160,5 @@ public:
|
|||
|
||||
int TimeAtFrame(int frame, agi::vfr::Time type = agi::vfr::EXACT) const;
|
||||
int FrameAtTime(int time, agi::vfr::Time type = agi::vfr::EXACT) const;
|
||||
std::shared_ptr<VideoFrame> GetFrame(int frame, bool raw) const;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue