SDcmWeb/webassembly/ffmpeg_mod.cc
2025-10-12 00:17:30 +09:00

720 lines
20 KiB
C++

//
// Emscripten/SDL2/OpenGLES2 sample that demonstrates simple geometry and shaders, mouse and touch input, and window resizing
//
// Setup:
// Install emscripten: http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html
//
// Build:
// emcc -std=c++11 hello_triangle.cpp events.cpp camera.cpp -s USE_SDL=2 -s FULL_ES2=1 -s WASM=0 -o hello_triangle.html
//
// Run:
// emrun hello_triangle.html
//
// Result:
// A colorful triangle. Left mouse pans, mouse wheel zooms in/out. Window is resizable.
//
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengles2.h>
//#include <SDL2/SDL_opengles2_gl2ext.h>
//#include <GLES3/gl3.h>
#include <string>
#include "events.h"
extern "C" {
#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/eval.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/dict.h"
#include "libavutil/fifo.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/time.h"
#include "libavutil/bprint.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavcodec/avfft.h"
#include "libavcodec/avcodec.h"
#include "libswresample/swresample.h"
}
typedef void (*callback_UpdateDcmImage) ();
callback_UpdateDcmImage callback_UpdateDcmImageComplete = NULL;
uint8_t* g_pImageData = NULL;
SwsContext *img_convert_ctx = NULL;
AVFormatContext* format_ctx = NULL;
AVCodecContext* codec_ctx = NULL;
int video_stream_index = -1;
std::string g_strFilename = "";
bool g_bLoadFile = false;
bool g_bChange = false;
EventHandler* g_pEventHandler = NULL;
GLuint textureObj = 0;
GLuint g_shaderProgramGray16 = 0;
GLuint g_shaderProgramRGB = 0;
// Vertex shader
GLint g_shaderPanGray16, g_shaderZoomGray16, g_shaderAspectGray16, g_shaderWindowCenterGray16, g_shaderWindowWidthGray16;
GLint g_shaderPanRGB, g_shaderZoomRGB, g_shaderAspectRGB, g_shaderWindowCenterRGB, g_shaderWindowWidthRGB;
int g_nColorType = 1;
int g_nWindowCenter = 0;
int g_nWindowWidth = 0;
int g_nPrevWindowCenter = 0;
int g_nPrevWindowWidth = 0;
Uint32 g_nCurrentFrame = 0;
int g_nTotalFrames = 0;
int g_nFrameWidth = 0;
int g_nFrameHeight = 0;
int g_nSamplesPerPixel = 0;
int g_nBitsAllocated = 0;
int g_nFrameSizeUncompressed = 0;
const GLchar* vertexSourceGray16 =
"uniform vec2 pan; \n"
"uniform float zoom; \n"
"uniform float aspect; \n"
"attribute vec4 position; \n"
"attribute vec2 a_texCoord; \n"
"varying vec2 texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = vec4(position.xyz, 1.0); \n"
" gl_Position.xy += pan; \n"
" gl_Position.xy *= zoom; \n"
" texCoord = a_texCoord; \n"
" gl_Position.y *= aspect; \n"
"} \n";
// Fragment/pixel shader
const GLchar* fragmentSourceGray16 =
"precision mediump float; \n"
"varying vec2 texCoord; \n"
"uniform sampler2D texSampler; \n"
"uniform float fWindowCenter; \n"
"uniform float fWindowWidth; \n"
"void main() \n"
"{ \n"
" vec4 colorOut = texture2D(texSampler, texCoord); \n"
" float fMin = fWindowCenter - fWindowWidth/2.0;\n"
" float fMax = fWindowCenter + fWindowWidth/2.0;\n"
" float fData = ( ((colorOut.a + colorOut.r*256.0)*256.0) - fMin)/(fMax-fMin); \n"
" fData = ( ((colorOut.a + colorOut.a*256.0)*256.0) - fMin)/(fMax-fMin); \n"
" fData = colorOut.r;\n"
" fData = (((colorOut.a * 256.0 + colorOut.r)*256.0) - fMin) / (fMax-fMin);"
" float fTmpData = fMin;\n"
" gl_FragColor = vec4(fData, fData, fData, 1.0); \n"
"} \n";
const GLchar* vertexSourceRGB =
"uniform vec2 panRGB; \n"
"uniform float zoomRGB; \n"
"uniform float aspectRGB; \n"
"attribute vec4 position; \n"
"attribute vec2 a_texCoord; \n"
"varying vec2 texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = vec4(position.xyz, 1.0); \n"
" gl_Position.xy += panRGB; \n"
" gl_Position.xy *= zoomRGB; \n"
" texCoord = a_texCoord; \n"
" gl_Position.y *= aspectRGB; \n"
"} \n";
// Fragment/pixel shader
const GLchar* fragmentSourceRGB =
"precision mediump float; \n"
"varying vec2 texCoord; \n"
"uniform sampler2D texSampler; \n"
"uniform float fWindowCenterRGB; \n"
"uniform float fWindowWidthRGB; \n"
"void main() \n"
"{ \n"
" vec4 colorOut = texture2D(texSampler, texCoord); \n"
" float fMin = fWindowCenterRGB - fWindowWidthRGB/2.0;\n"
" float fMax = fWindowCenterRGB + fWindowWidthRGB/2.0;\n"
" float fTestValue = (fMax - fMin);\n"
" float fR = (colorOut.r*256.0 - fMin) / (fMax-fMin);\n"
" float fG = (colorOut.g*256.0 - fMin) / (fMax-fMin);\n"
" float fB = (colorOut.b*256.0 - fMin) / (fMax-fMin);\n"
" gl_FragColor = vec4(fR, fG, fB, 1.0); \n"
//" gl_FragColor = vec4(colorOut.r/fTestValue, 1.0, 1.0, 1.0); \n"
"} \n";
void updateShader(EventHandler& eventHandler)
{
Camera& camera = eventHandler.camera();
printf("updateShader: g_nColorType=%d\n", g_nColorType);
if(g_nColorType==0)
{
glUseProgram(g_shaderProgramGray16);
glUniform2fv(g_shaderPanGray16, 1, camera.pan());
glUniform1f(g_shaderZoomGray16, camera.zoom());
glUniform1f(g_shaderAspectGray16, camera.aspect());
}
else if(g_nColorType==1)
{
glUseProgram(g_shaderProgramRGB);
glUniform2fv(g_shaderPanRGB, 1, camera.pan());
glUniform1f(g_shaderZoomRGB, camera.zoom());
glUniform1f(g_shaderAspectRGB, camera.aspect());
}
}
void onErrorData(void* arg)
{
printf("onErrorData %d\n", (int)arg);
}
void updateTextureGray16(int nWidth, int nHeight, void* pData)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, nWidth, nHeight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pData);
}
void updateTextureRGB(int nWidth, int nHeight, void* pData)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, nWidth, nHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, pData);
}
void updateWindowWidthLevelGray16(int nWidth, int nLevel)
{
glUniform1f(g_shaderWindowCenterGray16, (float)nLevel);
glUniform1f(g_shaderWindowWidthGray16, (float)nWidth);
}
void updateWindowWidthLevelRGB(int nWidth, int nLevel)
{
glUniform1f(g_shaderWindowCenterRGB, (float)nLevel);
glUniform1f(g_shaderWindowWidthRGB, (float)nWidth);
}
void initShaderGray16()
{
// Create and compile vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSourceGray16, NULL);
glCompileShader(vertexShader);
// Create and compile fragment shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSourceGray16, NULL);
glCompileShader(fragmentShader);
// Link vertex and fragment shader into shader program and use it
g_shaderProgramGray16 = glCreateProgram();
glAttachShader(g_shaderProgramGray16, vertexShader);
glAttachShader(g_shaderProgramGray16, fragmentShader);
glLinkProgram(g_shaderProgramGray16);
//glUseProgram(g_shaderProgramGray16);
// Get shader variables and initialize them
g_shaderPanGray16 = glGetUniformLocation(g_shaderProgramGray16, "pan");
g_shaderZoomGray16 = glGetUniformLocation(g_shaderProgramGray16, "zoom");
g_shaderAspectGray16 = glGetUniformLocation(g_shaderProgramGray16, "aspect");
g_shaderWindowCenterGray16 = glGetUniformLocation(g_shaderProgramGray16, "fWindowCenter");
g_shaderWindowWidthGray16 = glGetUniformLocation(g_shaderProgramGray16, "fWindowWidth");
glUniform1f(g_shaderWindowCenterGray16, 128.0f);
glUniform1f(g_shaderWindowWidthGray16, 255.0f);
//printf("pan:%d, zoom:%d, aspect:%d, g_shaderWindowCenterGray16:%d, g_shaderWindowWidthGray16:%d\n", g_shaderPanGray16, g_shaderZoomGray16, g_shaderAspectGray16, g_shaderWindowCenterGray16, g_shaderWindowWidthGray16);
}
void initShaderRGB()
{
// Create and compile vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSourceRGB, NULL);
glCompileShader(vertexShader);
// Create and compile fragment shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSourceRGB, NULL);
glCompileShader(fragmentShader);
// Link vertex and fragment shader into shader program and use it
g_shaderProgramRGB = glCreateProgram();
//printf("g_shaderProgramRGB: %d\n", g_shaderProgramRGB);
glAttachShader(g_shaderProgramRGB, vertexShader);
glAttachShader(g_shaderProgramRGB, fragmentShader);
glLinkProgram(g_shaderProgramRGB);
//glUseProgram(g_shaderProgramRGB);
// Get shader variables and initialize them
g_shaderPanRGB = glGetUniformLocation(g_shaderProgramRGB, "panRGB");
g_shaderZoomRGB = glGetUniformLocation(g_shaderProgramRGB, "zoomRGB");
g_shaderAspectRGB = glGetUniformLocation(g_shaderProgramRGB, "aspectRGB");
g_shaderWindowCenterRGB = glGetUniformLocation(g_shaderProgramRGB, "fWindowCenterRGB");
g_shaderWindowWidthRGB = glGetUniformLocation(g_shaderProgramRGB, "fWindowWidthRGB");
glUniform1f(g_shaderWindowCenterRGB, 128.0f);
glUniform1f(g_shaderWindowWidthRGB, 255.0f);
//printf("pan:%d, zoom:%d, aspect:%d, g_shaderWindowCenterRGB:%d, g_shaderWindowWidthRGB:%d\n", g_shaderPanRGB, g_shaderZoomRGB, g_shaderAspectRGB, g_shaderWindowCenterRGB, g_shaderWindowWidthRGB);
}
GLuint initShader(EventHandler& eventHandler)
{
initShaderGray16();
initShaderRGB();
updateShader(eventHandler);
g_pEventHandler = &eventHandler;
return g_shaderProgramGray16;
}
GLuint g_vbo = 0;
void initGeometry(GLuint shaderProgram)
{
// Create vertex buffer object and copy vertex data into it
//printf("g_vbo: %d\n", g_vbo);
glGenBuffers(1, &g_vbo);
glBindBuffer(GL_ARRAY_BUFFER, g_vbo);
GLfloat vertices[] =
{
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 1.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Specify the layout of the shader vertex data (positions only, 3 floats)
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
// glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (GLvoid*)0);
// glEnableVertexAttribArray(0);
GLint texAttrib = glGetAttribLocation(shaderProgram, "a_texCoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
//glEnableVertexAttribArray(2);
// glBindBuffer(GL_ARRAY_BUFFER, 0);
//printf("initGeometry(%d, %d)\n", posAttrib, texAttrib);
}
void PrintError()
{
int nError = 0;
nError = glGetError();
printf("Error Code: %d\n", nError);
}
void onLoadedData(void* arg, void* buffer, int nSize)
{
printf("onLoadedData %d, %d\n", (int)arg, nSize);
}
void initTextureGray16(void* pImageData)
{
//const Uint16* pImageData = NULL;
//g_pDcmDataset->findAndGetUint16Array(DCM_PixelData, pImageData);
int w = g_nFrameWidth;
int h = g_nFrameHeight;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
{
glGenTextures(1, &textureObj);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureObj);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
PrintError();
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pImageData);
PrintError();
GLint nTextureID = glGetUniformLocation(g_shaderProgramGray16, "texSampler");
//printf("texSampler: %d\n", nTextureID);
glActiveTexture(GL_TEXTURE0);
glUniform1i(nTextureID, 0);
}
}
void initTextureRGB(void* pImageData)
{
printf("initTextureRGB\n");
//const Uint8* pImageData = NULL;
//g_pDcmDataset->findAndGetUint8Array(DCM_PixelData, pImageData);
int w = g_nFrameWidth;
int h = g_nFrameHeight;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLint format = GL_RGB;
//printf("textureObj: %d\n", textureObj);
if(textureObj>=0)
{
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteTextures(1, &textureObj);
}
glGenTextures(1, &textureObj);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureObj);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
PrintError();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, pImageData);
PrintError();
GLint nTextureID = glGetUniformLocation(g_shaderProgramRGB, "texSampler");
//printf("texSampler: %d\n", nTextureID);
glActiveTexture(GL_TEXTURE0);
glUniform1i(nTextureID, 0);
}
void redraw(EventHandler& eventHandler)
{
if(g_bChange==true)
{
if(g_nColorType==0)
{
initGeometry(g_shaderProgramGray16);
glUseProgram(g_shaderProgramGray16);
initTextureGray16(g_pImageData);
updateShader(*g_pEventHandler);
}
else if(g_nColorType==1)
{
initGeometry(g_shaderProgramRGB);
glUseProgram(g_shaderProgramRGB);
initTextureRGB(g_pImageData);
updateShader(*g_pEventHandler);
}
g_bChange = false;
}
if(g_nTotalFrames>0)
{
if(g_nColorType==0)
{
printf("updateTextureRGB: %d\n", g_nCurrentFrame);
updateTextureGray16(g_nFrameWidth, g_nFrameHeight, g_pImageData);
}
else if(g_nColorType==1)
{
//printf("updateTextureRGB: %d, %d, %d, %d, %s\nerror: %s\n", g_nFrameWidth, g_nFrameHeight, g_nCurrentFrame, g_nFrameSizeUncompressed, decompressedColorModel.c_str(), ofTest.text());
updateTextureRGB(g_nFrameWidth, g_nFrameHeight, g_pImageData);
}
if(g_nCurrentFrame>=g_nTotalFrames)
{
g_nCurrentFrame = 0;
}
}
if(g_nColorType==0)
{
updateWindowWidthLevelGray16(g_nPrevWindowWidth, g_nPrevWindowCenter);
}
else if(g_nColorType==1)
{
updateWindowWidthLevelRGB(g_nPrevWindowWidth, g_nPrevWindowCenter);
}
// Clear screen
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// Draw the vertex buffer
glDrawArrays(GL_TRIANGLES, 0, 6);
// Swap front/back framebuffers
eventHandler.swapWindow();
}
void mainLoop(void* mainLoopArg)
{
EventHandler& eventHandler = *((EventHandler*)mainLoopArg);
eventHandler.processEvents();
if(g_bLoadFile==false && g_strFilename.size()>0)
{
AVDictionary *opts = NULL;
int ret = av_dict_set(&opts, "rtsp_transport", "tcp", 0);
// av_dict_set(&opts, "rtsp_transport", "tcp", 0);
// av_dict_set(&opts, "timeout", "5000", 0);
printf("UpdateDcmImage: av_dic_set\n");
g_strFilename = "http://localhost:5173/playlist_1080p.m3u8";
printf("filename: %s\n", g_strFilename.c_str());
//open RTSP
//
// printf("avformat_open_input: start1212121212\n");
// format_ctx = avformat_alloc_context();
//if (avformat_open_input(&format_ctx, g_strFilename.c_str(), NULL, &opts) != 0)
if (avformat_open_input(&format_ctx, g_strFilename.c_str(), NULL, NULL) != 0)
{
printf("Error avformat_open_input");
//return EXIT_FAILURE;
}
printf("avformat_open_input: finish\n");
av_dict_free(&opts);
callback_UpdateDcmImageComplete();
g_bLoadFile = true;
}
int nType = eventHandler.GetEventType();
if(nType==1 || nType==2)
{
float fDeltaX = eventHandler.GetDeltaX();
float fDeltaY = eventHandler.GetDeltaY();
g_nPrevWindowCenter = g_nWindowCenter+fDeltaY;
g_nPrevWindowWidth = g_nWindowWidth + fDeltaX;
}
else if(nType==3 || nType==4)
{
g_nWindowCenter = g_nPrevWindowCenter;
g_nWindowWidth = g_nPrevWindowWidth;
}
// Update shader if camera changed
if (eventHandler.camera().updated())
updateShader(eventHandler);
redraw(eventHandler);
}
#ifdef __cplusplus
#define EXTERN extern "C"
#else
#define EXTERN
#endif
EXTERN EMSCRIPTEN_KEEPALIVE int UpdateDcmImage(std::string strURL)
{
printf("UpdateDcmImage: %s\n", strURL.c_str());
g_strFilename = strURL;
/*
AVDictionary *opts = NULL;
int ret = av_dict_set(&opts, "rtsp_transport", "tcp", 0);
printf("UpdateDcmImage: av_dic_set\n");
//open RTSP
if (avformat_open_input(&format_ctx, strURL.c_str(), NULL, &opts) != 0)
{
printf("Error avformat_open_input");
return EXIT_FAILURE;
}
av_dict_free(&opts);
callback_UpdateDcmImageComplete();
*/
return 0;
}
EXTERN EMSCRIPTEN_KEEPALIVE int SetWindowWidthLevel(int nWindowCenter, int nWindowWidth)
{
printf("New nWindowCenter:%d, nWindowWidth:%d\n", nWindowCenter, nWindowWidth);
g_nWindowCenter = nWindowCenter;
g_nWindowWidth = nWindowWidth;
g_nPrevWindowCenter = g_nWindowCenter;
g_nPrevWindowWidth = g_nWindowWidth;
return 0;
}
EXTERN EMSCRIPTEN_KEEPALIVE int GetWindowWidth()
{
return g_nWindowWidth;
}
EXTERN EMSCRIPTEN_KEEPALIVE int GetWindowCenter()
{
return g_nWindowCenter;
}
EXTERN EMSCRIPTEN_KEEPALIVE bool SetCallbackUpdateDcmImageComplete(callback_UpdateDcmImage callback_)
{
printf("SetCallbackUpdateDcmImage: %x\n", callback_);
callback_UpdateDcmImageComplete = callback_;
return true;
}
int main(int argc, char** argv)
{
EventHandler eventHandler("dcm image viewer");
avdevice_register_all();
avformat_network_init();
if(g_pImageData==NULL)
{
g_pImageData = new uint8_t[1920*1080*3];
int i=0;
int j=0;
for(i=0 ; i<1080 ; i++)
{
for(j=0 ; j<1920 ; j++)
{
g_pImageData[(i*1920+j)*3+0] = 128;
g_pImageData[(i*1920+j)*3+1] = 128;
g_pImageData[(i*1920+j)*3+2] = 0;
}
}
}
// Initialize shader and geometry
GLuint shaderProgram = initShader(eventHandler);
//initTexture();
// Start the main loop
void* mainLoopArg = &eventHandler;
#ifdef __EMSCRIPTEN__
int fps = 0; // Use browser's requestAnimationFrame
emscripten_set_main_loop_arg(mainLoop, mainLoopArg, fps, true);
#else
while(true)
mainLoop(mainLoopArg);
#endif
glDeleteTextures(1, &textureObj);
glBindTexture(GL_TEXTURE_2D, 0);
if(g_pImageData!=NULL)
{
delete[] g_pImageData;
g_pImageData = NULL;
}
printf("exit!!!!! c++ dcm_image_mod");
return 0;
}