Due to work needs, the self-encapsulated ffmpeg-based video codec library shows that the SDL library is used. Can play local files or network streams, support multi-port playback, support text overlay, screenshots, video recording, etc.
Header file code:
#pragma once #ifdef __DLLEXPORT #define __DLL_EXP _declspec(dllexport) #else #define __DLL_EXP _declspec(dllimport) #endif #include <stdio.h> #include <string> using namespace std; //recording status enum RecordStatus { Idle, Recording, stop }; //Video storage format enum VideoFormat { MP4, AVI, }; //Image storage format enum PictureFormat { JPEG, PNG, BMP, }; //player state enum PlayStatus { Close, Playing, Pause }; // filter type enum FilterType { Time, Reticle, Text, other }; //color struct RGBAColor { BYTE R; BYTE G; BYTE B; BYTE A; }; //OSD font attribute structure struct OSDParameter { char* text; int fontSize; //Chinese character font size int fontFamily; //0=Black, 1=Italic, 2=Arial 3:Arial RGBAColor fontColor; // font color rgb representation RGBAColor backColor; // font background color rgb representation float x; //font coordinates x: width percentage 0-1 float y; //font coordinates y: height percentage 0-1 bool visible; //Is it visible }; //Format enum FrameFormat { AUDIO16, RGB32, YV12, UVVY, YUVJ420P }; struct FrameInfo { int width; //screen width, unit pixel. 0 if it is audio data; int height; //screen height. 0 if it is audio data; int stamp; //time stamp information, in milliseconds. FrameFormat format; //data type, 0: AUDIO16, 1: RGB32, 2: (YUV420P) YV12, 3: YUVJ420P int frameRate; //Real-time frame rate. }; /** * Function description: open video * @param nPort: playback channel number [0,31] * @param url: URL of video file or video stream * @param data: Image control handle, when recording in the background, assign NULL * * @return success/failure */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_OpenVideo(int nPort, const char* url, const void* hWnd); /** * Function description: start playing * @param nPort: playback channel number [0,31] * @param isRealTimePlay: Real-time playback, open when real-time playback is required, such as playing camera streams. When false, it will play at the frame rate. */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_StartPlay(int nPort, bool isRealTimePlay); /** * Function description: Pause playback * @param nPort: playback channel number [0,31] */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_PausePlay(int nPort); /** * Function description: close the video to release resources * @param nPort: playback channel number [0,31] */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_CloseVideo(int nPort); /** * Function description: set the relative position of the file play pointer (percentage) * @param nPort: playback channel number [0,31] * @param pos: playback time position 0-100 * @param fReleatePos: 0-100 */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetPlayPos(int nPort, float fReleatePos); /** * Function description: playback speed control * @param nPort: playback channel number [0,31] * @param speed: speed 0: normal playback 1: 1.25x speed 2: 1.5x speed 3: 1.75x speed 4: 2x speed 5: 0.75x speed 6: 0.5x speed 7: 0.25x speed */ extern "C" __declspec(dllexport) void _stdcall VideoPlayer_ChangeSpeed(int nPort, int speed); /** * Function description: Get the current playing time * @param nPort: playback channel number [0,31] * @return playback time unit: second */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_GetPlayedTime(int nPort); /** * Function description: Play window zoom * @param nPort: playback channel number [0,31] * @return success/failure */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_ResizeWindow(int nPort); /** * Function description: set recording parameters * @param nPort: playback channel number [0,31] * @param fps: video frame rate * @param quality: Image quality (0-10) The higher the quality, the better the memory usage. When set to 0, it is the automatic code rate * @param duration: the duration of a single file (min), the default is 60 minutes * @param frameExtractionMode: Frame extraction mode 0: No frame extraction, encoding in fps; 1: 1/2 frame rate, frame extraction in fps/2 (guarantee fps/2 is an integer, otherwise frame loss will occur) * @param format: storage format, the default is mp4 * * @return success/failure */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetRecordParameter(int nPort,int fps, float quality = 5, int duration = 60, int frameExtractionMode = 0, VideoFormat format= VideoFormat::MP4); /** * Function description: start recording * @param nPort: playback channel number [0,31] * @param path: The video save path contains the file name * * @return success/failure */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_StartRecord(int nPort, const char* path); /** * Function description: end recording * @param nPort: playback channel number [0,31] */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_StopRecord(int nPort); /** * Function description: video screenshot * @param nPort: playback channel number [0,31] * @param path: The path where the image is saved, without the suffix name * @param format: image format, the default is jpeg * * @return success/failure */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_ShotImage(int nPort, const char* path, PictureFormat format= PictureFormat::JPEG); /** * Function description: set the OSD superimposed text of a certain line * @param nPort: playback channel number [0,31] * @param osdID: OSD text serial number * @param para: osd attribute * * @return success/failure */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetOSDText(int nPort, int osdID, OSDParameter osdParam); /** * Function description: set all OSD texts (20 lines in total) * @param nPort: playback channel number [0,31] * @param para: osd attribute * * @return success/failure */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetAllOSDTexts(int nPort, OSDParameter osdParams[]); /** * Function description: clear all OSD text * @param nPort: playback channel number [0,31] * * @return success/failure */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_ClearOSDText(int nPort); /** * Function description: Set the decoding buffer queue size * @param nPort: playback channel number [0,31] * @param size: The default is 10, setting too small will cause frame loss, setting too large may cause screen delay * * @return success/failure */ extern "C" __declspec(dllexport) void _stdcall VideoPlayer_SetDecodedBufferSize(int nPort, int size); /** * Function description: play a single frame backwards * @param nPort: playback channel number [0,31] */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_NextFrame(int nPort); /** * Function description: play forward by single frame * @param nPort: playback channel number [0,31] */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_PrevFrame(int nPort); /** * Function description: jump video to a certain time position * @param nPort: playback channel number [0,31] * @param pos: video position percentage */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetPlayPos(int nPort, float pos); /** * Function description: display/hide current system time * @param nPort: playback channel number [0,31] * @param visible: whether to display * @param xPos: coordinate position X, width percentage * @param yPos: coordinate position Y, height percentage * @param fontSize: font size, default 50 */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetDateTime(int nPort, bool visible, float xPos, float yPos, int fontSize=50); /** * Function description: current decoding completion data callback * @param nPort: playback channel number [0,31] * @param pBuf: yuv data pointer * @param nSize: data size * @param pFrameInfo: frame information */ typedef void(_stdcall* DecodeCallBack)(int nPort, const unsigned char* pBuf, int nSize, FrameInfo & amp; pFrameInfo); /** * Function description: set the decoding callback function * @param nPort: playback channel number [0,31] * @param pDecodeProc: callback function */ extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetDecCallBack(int nPort, DecodeCallBack pDecodeProc); /** * Function description: draw text, graphics, etc. in the display handle window * @param nPort: playback channel number [0,31] * @param hWnd: video window handle, used to create GDI * @param width: video window width * @param height: video window height */ typedef void(_stdcall* DrawCallBack)(int nPort, const void* hWnd,int width,int height); extern "C" __declspec(dllexport) bool _stdcall VideoPlayer_SetDrawCallBack(int nPort, DrawCallBack pDrawProc);
The library supports C++ and C# calling, the following is the method of C# calling:
using System; using System.Collections.Generic; using System. ComponentModel; using System.Data; using System. Drawing; using System. Linq; using System. Text; using System. Threading. Tasks; using System. Windows. Forms; using VideoPlayDemo.Onvif; using static VideoPlayDemo.MYVideoPlay; namespace VideoPlayDemo { public partial class Form1 : Form { const int PLAY_PORT1 = 0; const int PLAY_PORT2 = 1; public event MYVideoPlay. DecodeCallBack decodeCallBack; public event MYVideoPlay.DrawCallBack drawCallBack; bool[] isRecording = new bool[2]; bool[] isOpened = new bool[2]; MYVideoPlay.OSDParameter[] OSDParameters1 = new MYVideoPlay.OSDParameter[20]; MYVideoPlay.OSDParameter[] OSDParameters2 = new MYVideoPlay.OSDParameter[20]; public Form1() { InitializeComponent(); Timer timer = new Timer(); timer. Interval = 100; timer. Enabled = true; timer.Tick += Timer_Tick; decodeCallBack + = new MYVideoPlay. DecodeCallBack(Form1_decodeCallBack); drawCallBack + = new MYVideoPlay. DrawCallBack(Form1_drawCallBack); //initialization for (int i = 0; i < 20; i ++ ) { OSDParameters1[i] = new MYVideoPlay. OSDParameter(); OSDParameters1[i].visible = false; OSDParameters1[i].text = "test Chinese" + i.ToString(); OSDParameters1[i].fontSize = 100; OSDParameters1[i].fontFamily = 0; OSDParameters1[i].fontColor = new MYVideoPlay.RGBAColor(Color.White); OSDParameters1[i].backColor = new MYVideoPlay.RGBAColor(Color.Transparent); OSDParameters2[i] = new MYVideoPlay. OSDParameter(); OSDParameters2[i].visible = false; OSDParameters2[i].text = "test Chinese" + i.ToString(); OSDParameters2[i].fontSize = 100; OSDParameters2[i].fontFamily = 0; OSDParameters2[i].fontColor = new MYVideoPlay.RGBAColor(Color.Yellow); OSDParameters2[i].backColor = new MYVideoPlay.RGBAColor(Color.Transparent); } } #region Video Playback Control Methods /// <summary> /// Open the video /// </summary> /// <param name="port"></param> public bool OpenVideo(int port, string url, IntPtr intPtr) { bool ret = false; ret = MYVideoPlay.VideoPlayer_SetDecCallBack(port, decodeCallBack); if (!ret) { MessageBox.Show("Failed to set the decoding callback function!"); return ret; } ret = MYVideoPlay.VideoPlayer_SetDrawCallBack(port, drawCallBack); if (!ret) { MessageBox.Show("Failed to set the drawing callback function!"); return ret; } ret = MYVideoPlay.VideoPlayer_OpenVideo(port, url, intPtr); if (!ret) { MessageBox.Show("Failed to open the video!"); return ret; } ret = MYVideoPlay.VideoPlayer_StartPlay(port,false); if (!ret) { MessageBox.Show("Play failed!"); return ret; } // overlay time // ret = MYVideoPlay.VideoPlayer_SetDateTime(port, true, 0.01f, 0.01f,70); return ret; } /// <summary> /// Close the video /// </summary> /// <param name="port"></param> private bool CloseVideo(int port) { return MYVideoPlay. VideoPlayer_CloseVideo(port); } /// <summary> /// Start recording frame rate 60 /// </summary> /// <param name="port"></param> /// <param name="halfRate"></param> private bool StartRecord(int port, bool halfRate) { bool ret = false; if(halfRate) ret = MYVideoPlay.VideoPlayer_SetRecordParameter(port, 60, 5, 60,1); else ret = MYVideoPlay.VideoPlayer_SetRecordParameter(port, 60, 5, 60, 0); string path = string.Format("d:\video_{0}", port); ret = MYVideoPlay.VideoPlayer_StartRecord(port, path); if (!ret) MessageBox.Show("Failed to start recording!"); return ret; } /// <summary> /// Stop recording /// </summary> /// <param name="port"></param> private bool StopRecord(int port) { bool ret = MYVideoPlay. VideoPlayer_StopRecord(port); return ret; } /// <summary> /// screenshot /// </summary> /// <param name="port"></param> /// <returns></returns> private bool ShotImage(int port) { bool ret = MYVideoPlay.VideoPlayer_ShotImage(port, "d:\" + port.ToString(), MYVideoPlay.PictureFormat.JPEG); return ret; } int[] frameRates = new int[4]; private void Form1_decodeCallBack(int nPort, IntPtr pBuf, int nSize, ref MYVideoPlay. FrameInfo pFrameInfo) { frameRates[nPort] = pFrameInfo. frameRate; this.Invoke((Action) delegate { this.lbFPS1.Text = frameRates[0].ToString() + "fps"; this.lbFPS2.Text = frameRates[1].ToString() + "fps"; }); } private void Form1_drawCallBack(int nPort, IntPtr hWnd, int width, int height) { } #endregion /// <summary> /// Open the video /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnOpenVideo_Click(object sender, EventArgs e) { Button btn = sender as Button; int n = int.Parse(btn.Tag.ToString()); if (isOpened[n]) return; string url=""; IntPtr intPtr = IntPtr. Zero; switch (n) { case 0: url = textBox1.Text;intPtr = pnlVideo1.Handle; break; case 1: url = textBox2.Text;intPtr = pnlVideo2.Handle; break; } Task task = new Task(() => { // Set a larger buffer for caching when live streaming (not camera streaming), otherwise mosaics will appear MYVideoPlay.VideoPlayer_SetDecodedBufferSize(n, 250); isOpened[n] = OpenVideo(n,url,intPtr); }); task. Start(); } /// <summary> /// Close the video /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnCloseVideo_Click(object sender, EventArgs e) { Button btn = sender as Button; int n = int.Parse(btn.Tag.ToString()); if (!isOpened[n]) return; bool ret = CloseVideo(n); isOpened[n] = !ret; } /// <summary> /// start recording /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnStartRecord_Click(object sender, EventArgs e) { Button btn = sender as Button; int n = int.Parse(btn.Tag.ToString()); if (isRecording[n] || !isOpened[n]) return; if (n == 0) isRecording[n] = StartRecord(n, true); else isRecording[n] = StartRecord(n, false); } /// <summary> /// Stop recording /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnStopRecord_Click(object sender, EventArgs e) { Button btn = sender as Button; int n = int.Parse(btn.Tag.ToString()); if (!isRecording[n] || !isOpened[n]) return; bool ret = StopRecord(n); isRecording[n] = !ret; } /// <summary> /// screenshot /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnShotImage_Click(object sender, EventArgs e) { Button btn = sender as Button; int n = int.Parse(btn.Tag.ToString()); ShotImage(n); } /// <summary> /// Overlay character test /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Timer_Tick(object sender, EventArgs e) { Random rd = new Random(); bool ret = false; if (isOpened[PLAY_PORT1]) { OSDParameters1[0].visible = OSDParameters1[1].visible = true; OSDParameters1[0].x = (float)rd.NextDouble(); OSDParameters1[0].y = (float)rd.NextDouble(); OSDParameters1[1].x = (float)rd.NextDouble(); OSDParameters1[1].y = (float)rd.NextDouble(); //ZYVideoPlay.VideoPlayer_SetAllOSDTexts(PLAY_PORT1, OSDParameters1); } if (isOpened[PLAY_PORT2]) { OSDParameters2[0].visible = OSDParameters2[1].visible = true; OSDParameters2[0].x = (float)rd.NextDouble(); OSDParameters2[0].y = (float)rd.NextDouble(); OSDParameters2[1].x = (float)rd.NextDouble(); OSDParameters2[1].y = (float)rd.NextDouble(); // ret = ZYVideoPlay. VideoPlayer_SetAllOSDTexts(PLAY_PORT2, OSDParameters2); } } private void timer1_Tick(object sender, EventArgs e) { if (isRecording[PLAY_PORT1]) { if (DateTime. Now. Millisecond < 500) lbRec1.Visible = true; else lbRec1.Visible = false; } else lbRec1.Visible = false; if (isRecording[PLAY_PORT2]) { if (DateTime. Now. Millisecond < 500) lbRec2.Visible = true; else lbRec2. Visible = false; } else lbRec2. Visible = false; } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { for(int i=0;i<2;i++) { if (isOpened[i]) CloseVideo(i); } } } }