Cleanup Media Player

This commit is contained in:
brunoherbelin
2020-03-22 23:33:29 +01:00
parent 31e2b6da79
commit ca0db135e7
7 changed files with 125 additions and 52 deletions

View File

@@ -215,7 +215,7 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 dura
// how many pixels to represent one frame step?
float tick_step_pixels = timeline_bbox.GetWidth() * step_;
// while there is less than 3 pixels between two tick marks (or at last optimal tick mark)
for ( int i=0; i<10 && tick_step_pixels < 3.f; ++i )
for ( int i=0; i<10 && tick_step_pixels < 5.f; ++i )
{
// try to use the optimal tick marks pre-defined
tick_step = optimal_tick_marks[i];

View File

@@ -24,8 +24,6 @@
// opengl texture
static GLuint tex_index_black = 0;
static GstStaticCaps gl_render_caps = GST_STATIC_CAPS ("video/x-raw(memory:GLMemory),format=RGBA,texture-target=2D");
static GstStaticCaps frame_render_caps = GST_STATIC_CAPS ("video/x-raw,format=RGB");
GLuint blackTexture()
{
@@ -47,6 +45,7 @@ MediaPlayer::MediaPlayer(string name) : id(name)
ready = false;
seekable = false;
isimage = false;
interlaced = false;
pipeline = nullptr;
discoverer = nullptr;
@@ -99,7 +98,7 @@ void MediaPlayer::Open(string uri)
GError *err = NULL;
discoverer = gst_discoverer_new (5 * GST_SECOND, &err);
if (!discoverer) {
Log::Warning("Error creating discoverer instance: %s\n", err->message);
Log::Warning("MediaPlayer Error creating discoverer instance: %s\n", err->message);
g_clear_error (&err);
return;
}
@@ -113,7 +112,7 @@ void MediaPlayer::Open(string uri)
gst_discoverer_start(discoverer);
// Add the request to process asynchronously the URI
if (!gst_discoverer_discover_uri_async (discoverer, uri.c_str())) {
Log::Warning("Failed to start discovering URI '%s'\n", uri.c_str());
Log::Warning("MediaPlayer %s Failed to start discovering URI '%s'\n", id.c_str(), uri.c_str());
g_object_unref (discoverer);
discoverer = nullptr;
}
@@ -125,24 +124,26 @@ void MediaPlayer::Open(string uri)
void MediaPlayer::execute_open()
{
// build string describing pipeline
string description = "uridecodebin uri=" + uri + " name=decoder ! videoconvert ! "
"video/x-raw,format=RGB ! appsink name=sink";
string description = "uridecodebin uri=" + uri + " name=decoder !";
if (interlaced)
description += " deinterlace !";
description += " videoconvert ! appsink name=sink";
// parse pipeline descriptor
GError *error = NULL;
pipeline = gst_parse_launch (description.c_str(), &error);
if (error != NULL) {
Log::Warning("Could not construct pipeline %s:\n%s\n", description.c_str(), error->message);
Log::Warning("MediaPlayer %s Could not construct pipeline %s:\n%s", id.c_str(), description.c_str(), error->message);
g_clear_error (&error);
return;
}
g_object_set(G_OBJECT(pipeline), "name", id.c_str(), NULL);
// GstCaps *caps = gst_static_caps_get (&frame_render_caps);
string capstring = "video/x-raw,format=RGB,width="+ std::to_string(width) + ",height=" + std::to_string(height);
string capstring = "video/x-raw,format=RGBA,width="+ std::to_string(width) + ",height=" + std::to_string(height);
GstCaps *caps = gst_caps_from_string(capstring.c_str());
if (!gst_video_info_from_caps (&v_frame_video_info, caps)) {
Log::Warning("%s: Could not configure MediaPlayer video frame info\n", gst_element_get_name(pipeline));
Log::Warning("MediaPlayer %s Could not configure video frame info", id.c_str());
return;
}
@@ -167,7 +168,7 @@ void MediaPlayer::execute_open()
gst_object_unref (sink);
}
else {
Log::Warning("%s: Could not configure MediaPlayer sink\n", gst_element_get_name(pipeline));
Log::Warning("MediaPlayer %s Could not configure sink", id.c_str());
return;
}
gst_caps_unref (caps);
@@ -178,15 +179,13 @@ void MediaPlayer::execute_open()
// set to desired state (PLAY or PAUSE)
GstStateChangeReturn ret = gst_element_set_state (pipeline, desired_state);
if (ret == GST_STATE_CHANGE_FAILURE) {
Log::Warning("%s: Failed to open media %s \n%s\n", gst_element_get_name(pipeline), uri.c_str(), discoverer_message.str().c_str());
}
else {
// all good
Log::Info("%s: Media Player openned %s\n", gst_element_get_name(pipeline), uri.c_str());
ready = true;
Log::Warning("MediaPlayer %s Could not open %s", id.c_str(), uri.c_str());
return;
}
discoverer_message.clear();
// all good
Log::Info("MediaPlayer %s Open %s (%s %d x %d)", id.c_str(), uri.c_str(), codec_name.c_str(), width, height);
ready = true;
}
bool MediaPlayer::isOpen() const
@@ -249,7 +248,7 @@ guint MediaPlayer::Height() const
float MediaPlayer::AspectRatio() const
{
return static_cast<float>(width) / static_cast<float>(height);
return static_cast<float>(par_width) / static_cast<float>(height);
}
GstClockTime MediaPlayer::Position()
@@ -293,13 +292,13 @@ void MediaPlayer::Play(bool on)
// all ready, apply state change immediately
GstStateChangeReturn ret = gst_element_set_state (pipeline, desired_state);
if (ret == GST_STATE_CHANGE_FAILURE) {
Log::Warning("Failed to start up Media %s\n", gst_element_get_name(pipeline));
Log::Warning("MediaPlayer %s Failed to start", gst_element_get_name(pipeline));
}
#ifdef MEDIA_PLAYER_DEBUG
else if (on)
Log::Info("Start Media %s\n", gst_element_get_name(pipeline));
Log::Info("MediaPlayer %s Start", gst_element_get_name(pipeline));
else
Log::Info("Stop Media %s\n", gst_element_get_name(pipeline));
Log::Info("MediaPlayer %s Stop", gst_element_get_name(pipeline));
#endif
}
@@ -457,16 +456,16 @@ void MediaPlayer::Update()
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &textureindex);
glBindTexture(GL_TEXTURE_2D, textureindex);
glPixelStorei(GL_UNPACK_ALIGNMENT, 3);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height,
0, GL_RGB, GL_UNSIGNED_BYTE, v_frame.data[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, v_frame.data[0]);
}
else // bind texture
{
glBindTexture(GL_TEXTURE_2D, textureindex);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
GL_RGB, GL_UNSIGNED_BYTE, v_frame.data[0]);
GL_RGBA, GL_UNSIGNED_BYTE, v_frame.data[0]);
}
// sync with callback_pull_last_sample_video
@@ -533,7 +532,7 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
else if ( ABS_DIFF(target, Position()) < frame_duration) {
// ignore request
#ifdef MEDIA_PLAYER_DEBUG
Log::Info("%s: Media Player ignored seek to current position\n", id.c_str());
Log::Info("MediaPlayer %s Ignored seek to current position", id.c_str());
#endif
return;
}
@@ -555,10 +554,10 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
// Send the event (ASYNC)
if (seek_event && !gst_element_send_event(pipeline, seek_event) )
Log::Info("Seek failed in Media %s\n", gst_element_get_name(pipeline));
Log::Warning("MediaPlayer %s Seek failed", gst_element_get_name(pipeline));
#ifdef MEDIA_PLAYER_DEBUG
else
Log::Info("Seek Media %s %ld %f\n", gst_element_get_name(pipeline), seek_pos, rate);
Log::Info("MediaPlayer %s Seek %ld %f", gst_element_get_name(pipeline), seek_pos, rate);
#endif
}
@@ -583,6 +582,11 @@ double MediaPlayer::PlaySpeed() const
}
std::string MediaPlayer::Codec() const
{
return codec_name;
}
double MediaPlayer::FrameRate() const
{
return framerate;
@@ -604,7 +608,7 @@ bool MediaPlayer::fill_v_frame(GstBuffer *buf)
// get the frame from buffer
if ( !gst_video_frame_map (&v_frame, &v_frame_video_info, buf, GST_MAP_READ ) ) {
Log::Info("Failed to map the video buffer");
Log::Info("MediaPlayer %s Failed to map the video buffer");
return false;
}
@@ -679,6 +683,9 @@ void MediaPlayer::callback_end_of_video (GstElement *bin, MediaPlayer *m)
void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, MediaPlayer *m)
{
if (!m)
return;
// handle general errors
const gchar *uri = gst_discoverer_info_get_uri (info);
GstDiscovererResult result = gst_discoverer_info_get_result (info);
@@ -699,7 +706,7 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
{
const GstStructure *s = gst_discoverer_info_get_misc (info);
gchar *str = gst_structure_to_string (s);
m->discoverer_message << "Missing plugin " << str;
m->discoverer_message << "Unknown file format / " << str;
g_free (str);
}
break;
@@ -707,7 +714,7 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
break;
}
// no error, handle information found
if ( result == GST_DISCOVERER_OK && m) {
if ( result == GST_DISCOVERER_OK ) {
// look for video stream at that uri
bool foundvideostream = false;
@@ -717,10 +724,16 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
GstDiscovererStreamInfo *tmpinf = (GstDiscovererStreamInfo *) tmp->data;
if ( GST_IS_DISCOVERER_VIDEO_INFO(tmpinf) )
{
// found a video / image stream : fill-in information
GstDiscovererVideoInfo* vinfo = GST_DISCOVERER_VIDEO_INFO(tmpinf);
m->width = gst_discoverer_video_info_get_width(vinfo);
m->height = gst_discoverer_video_info_get_height(vinfo);
m->isimage = gst_discoverer_video_info_is_image(vinfo);
m->interlaced = gst_discoverer_video_info_is_interlaced(vinfo);
guint parn = gst_discoverer_video_info_get_par_num(vinfo);
guint pard = gst_discoverer_video_info_get_par_denom(vinfo);
m->par_width = (m->width * parn) / pard;
// if its a video, it duration, framerate, etc.
if ( !m->isimage ) {
m->duration = gst_discoverer_info_get_duration (info);
m->seekable = gst_discoverer_info_get_seekable (info);
@@ -729,10 +742,27 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
m->framerate = static_cast<double>(frn) / static_cast<double>(frd);
m->frame_duration = (GST_SECOND * static_cast<guint64>(frd)) / (static_cast<guint64>(frn));
}
// try to fill-in the codec information
GstCaps *caps = gst_discoverer_stream_info_get_caps (tmpinf);
if (caps) {
m->codec_name = std::string( gst_pb_utils_get_codec_description(caps) );
gst_caps_unref (caps);
}
// const GstTagList *tags = gst_discoverer_stream_info_get_tags(tmpinf);
// if ( tags ) {
// gchar *container = NULL;
// gst_tag_list_get_string(tags, GST_TAG_CONTAINER_FORMAT, &container);
// if (container) m->codec_name = std::string(container) + " ";
// gchar *codec = NULL;
// gst_tag_list_get_string(tags, GST_TAG_VIDEO_CODEC, &codec);
// if (!codec) gst_tag_list_get_string (tags, GST_TAG_CODEC, &codec);
// if (codec) m->codec_name += std::string(codec);
// }
// exit loop
foundvideostream = true;
}
}
gst_discoverer_stream_info_list_free (streams);
gst_discoverer_stream_info_list_free(streams);
if (!foundvideostream) {
m->discoverer_message << "No video stream.";
@@ -744,8 +774,15 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
void MediaPlayer::callback_discoverer_finished(GstDiscoverer *discoverer, MediaPlayer *m)
{
// finished the discoverer : finalize open status
if (m)
m->execute_open();
if (m) {
// no error message, open media
if ( m->discoverer_message.str().empty())
m->execute_open();
else {
Log::Warning("MediaPlayer %s Failed to open %s\n%s", m->id.c_str(), m->uri.c_str(), m->discoverer_message.str().c_str());
m->discoverer_message.clear();
}
}
}
TimeCounter::TimeCounter() {

View File

@@ -179,6 +179,10 @@ public:
* Get framerate of the media
* */
double FrameRate() const;
/**
* Get name of Codec of the media
* */
std::string Codec() const;
/**
* Get rendering update framerate
* measured during play
@@ -212,6 +216,7 @@ private:
guint textureindex;
guint width;
guint height;
guint par_width; // width to match pixel aspect ratio
GstClockTime position;
GstClockTime start_position;
GstClockTime duration;
@@ -224,6 +229,7 @@ private:
GstElement *pipeline;
GstDiscoverer *discoverer;
std::stringstream discoverer_message;
std::string codec_name;
GstVideoFrame v_frame;
GstVideoInfo v_frame_video_info;
std::atomic<bool> v_frame_is_full;
@@ -235,6 +241,7 @@ private:
bool ready;
bool seekable;
bool isimage;
bool interlaced;
void execute_open();
void execute_loop_command();

View File

@@ -1,5 +1,5 @@
#ifndef vlmixer_shader
#define vlmixer_shader
#ifndef __SHADER_H_
#define __SHADER_H_
#include <string>
#include <vector>
@@ -28,4 +28,4 @@ private:
};
#endif /* vlmixer_shader */
#endif /* __SHADER_H_ */

View File

@@ -609,7 +609,7 @@ void MainWindow::Render()
ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver);
ImGui::Begin( ICON_FA_DOT_CIRCLE " v-mix", NULL, ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoCollapse);
ImGui::Begin( ICON_FA_CIRCLE_NOTCH " v-mix", NULL, ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoCollapse);
// Menu Bar
if (ImGui::BeginMenuBar())
@@ -738,8 +738,35 @@ void UserInterface::OpenTextEditor(std::string text)
currentTextEdit = text;
auto lang = TextEditor::LanguageDefinition::GLSL();
editor.SetLanguageDefinition(lang);
static const char* const keywords[] = {
"discard", "attribute", "varying", "uniform", "in", "out", "inout", "bvec2", "bvec3", "bvec4", "dvec2",
"dvec3", "dvec4", "ivec2", "ivec3", "ivec4", "uvec2", "uvec3", "uvec4", "vec2", "vec3", "vec4", "mat2",
"mat3", "mat4", "dmat2", "dmat3", "dmat4", "sampler1D", "sampler2D", "sampler3D", "samplerCUBE", "samplerbuffer",
"sampler1DArray", "sampler2DArray", "sampler1DShadow", "sampler2DShadow", "vec4", "vec4", "smooth", "flat",
"precise", "coherent", "uint", "struct", "switch", "unsigned", "void", "volatile", "while", "readonly"
};
for (auto& k : keywords)
lang.mKeywords.insert(k);
static const char* const identifiers[] = {
"radians", "degrees", "sin", "cos", "tan", "asin", "acos", "atan", "pow", "exp2", "log2", "sqrt", "inversesqrt",
"abs", "sign", "floor", "ceil", "fract", "mod", "min", "max", "clamp", "mix", "step", "smoothstep", "length", "distance",
"dot", "cross", "normalize", "ftransform", "faceforward", "reflect", "matrixcompmult", "lessThan", "lessThanEqual",
"greaterThan", "greaterThanEqual", "equal", "notEqual", "any", "all", "not", "texture1D", "texture1DProj", "texture1DLod",
"texture1DProjLod", "texture", "texture2D", "texture2DProj", "texture2DLod", "texture2DProjLod", "texture3D",
"texture3DProj", "texture3DLod", "texture3DProjLod", "textureCube", "textureCubeLod", "shadow1D", "shadow1DProj",
"shadow1DLod", "shadow1DProjLod", "shadow2D", "shadow2DProj", "shadow2DLod", "shadow2DProjLod",
"dFdx", "dFdy", "fwidth", "noise1", "noise2", "noise3", "noise4", "refract", "exp", "log", "mainImage",
};
for (auto& k : identifiers)
{
TextEditor::Identifier id;
id.mDeclaration = "Added function";
lang.mIdentifiers.insert(std::make_pair(std::string(k), id));
}
editor.SetLanguageDefinition(lang);
editor.SetText(currentTextEdit);
}

View File

@@ -328,7 +328,7 @@ void drawMediaPlayer()
}
// display info
ImGui::Text("Dimension %d x %d", testmedia.Width(), testmedia.Height());
ImGui::Text("%s %d x %d", testmedia.Codec().c_str(), testmedia.Width(), testmedia.Height());
ImGui::Text("Framerate %.2f / %.2f", testmedia.UpdateFrameRate() , testmedia.FrameRate() );
ImGui::End();
@@ -364,10 +364,9 @@ int main(int, char**)
#endif
// 1
// testmedia.Open("file:///home/bhbn/Images/2014-10-18_16-46-47.jpg");
// testmedia.Open("file:///home/bhbn/Videos/balls.gif");
// testmedia.Open("file:///home/bhbn/Videos/SIGGRAPH92_1.avi");
testmedia.Open("file:///home/bhbn/Videos/fish.mp4");
// testmedia.Open("file:///home/bhbn/Videos/MOV001.MOD");
testmedia.Open("file:///home/bhbn/Videos/TestFormats/Commodore64GameReviewMoondust.flv");
// testmedia.Open("file:///home/bhbn/Videos/fish.mp4");
// testmedia.Open("file:///home/bhbn/Videos/jean/Solitude1080p.mov");
// testmedia.Open("file:///home/bhbn/Videos/TearsOfSteel_720p_h265.mkv");
// testmedia.Open("file:///home/bhbn/Videos/TestFormats/_h264GoldenLamps.mkv");
@@ -380,8 +379,10 @@ int main(int, char**)
Rendering::manager().AddDrawCallback(drawMediaPlayer);
// 2
testmedia2.Open("file:///home/bhbn/Videos/iss.mov");
// testmedia2.Open("file:///home/bhbn/Images/svg/drawing.svg");
// testmedia2.Open("file:///home/bhbn/Images/Butterfly.gif");
// testmedia2.Open("file:///home/bhbn/Images/Scan-090614-0022.jpg");
testmedia2.Open("file:///home/bhbn/Images/svg/abstract.svg");
// testmedia2.Open("file:///home/bhbn/Images/4k/colors-3840x2160-splash-4k-18458.jpg");
// testmedia2.Open("file:///home/bhbn/Videos/Upgrade.2018.720p.AMZN.WEB-DL.DDP5.1.H.264-NTG.m4v");
testmedia2.Play(true);
// create our geometries
@@ -393,9 +394,9 @@ int main(int, char**)
// textureimagepng = loadPNG("/home/bhbn/Videos/iss_snap.png", &texturear);
// init shader
rendering_shader.load("shaders/texture-shader.vs", "shaders/texture-shader.fs");
rendering_shader.load("shaders/texture-shader.vs", "shaders/texture-shader.fs");
UserInterface::manager().OpenTextEditor( Resource::getText("shaders/texture-shader.vs") );
UserInterface::manager().OpenTextEditor( Resource::getText("shaders/texture-shader.fs") );
///
/// Main LOOP

View File

@@ -12,7 +12,8 @@ uniform float brightness;
void main()
{
vec4 texturecolor = texture(sourceTexture, vertexUV.xy);
vec3 transformedRGB = mix(vec3(0.62), texturecolor.rgb, contrast + 1.0) + brightness;
FragColor = vec4(color, 1.0) * vec4(transformedRGB, texturecolor.a);
transformedRGB *= color;
FragColor = vec4(transformedRGB, texturecolor.a);
}