
Recherche avancée
Autres articles (54)
-
Websites made with MediaSPIP
2 mai 2011, parThis page lists some websites based on MediaSPIP.
-
Creating farms of unique websites
13 avril 2011, parMediaSPIP platforms can be installed as a farm, with a single "core" hosted on a dedicated server and used by multiple websites.
This allows (among other things) : implementation costs to be shared between several different projects / individuals rapid deployment of multiple unique sites creation of groups of like-minded sites, making it possible to browse media in a more controlled and selective environment than the major "open" (...) -
Contribute to a better visual interface
13 avril 2011MediaSPIP is based on a system of themes and templates. Templates define the placement of information on the page, and can be adapted to a wide range of uses. Themes define the overall graphic appearance of the site.
Anyone can submit a new graphic theme or template and make it available to the MediaSPIP community.
Sur d’autres sites (9098)
-
Getting and decoding video by RTP H264
29 novembre 2023, par AlekseiKraevParsing RTP H264.
WINAPI C. A queue from C++ has been applied, I repent.


RTP is generated using FFMPEG with the following command :
ffmpeg.exe -f gdigrab -framerate 25 -i desktop -s 853x480 -b:v 120000 -c:v libx264 -f rtp rtp ://127.0.0.1:8080


Parsing the incoming RTP/h264 stream and converting it to an RGB matrix.


video_H264_decode.h


#pragma once
#ifndef _VIDEO_H264_DECODE_SEND_H // Блокируем повторное включение этого модуля
#define _VIDEO_H264_DECODE_SEND_H
//******************************************************************************
// Section include
//******************************************************************************
#include "main.h"
#include 
//******************************************************************************
// Constants
//******************************************************************************

//******************************************************************************
// Type
//******************************************************************************
typedef struct {
 unsigned char* data;
 int size;
}RTPData_DType;

typedef struct 
{
 union
 {
 struct
 {
 char V:2; //Версия
 char P:1; //заполнение
 char X:1; //расширение
 char CC:4; //количество CSRC

 char M:1; //маркер (флаг последнего пакета AU),
 char PT:7; //полезная нагрузка (тип данных носителя полезной нагрузки RTP, H264 = 96)

 short sequence_number; //Порядковый номер: порядковый номер пакета RTP, увеличенный на 1.
 int time_stamp; //временная метка выборки медиа. 
 int SSRC; //Пакет данных имеет одинаковое происхождение.
 };
 unsigned char data[12];
 };
}RTPHeader_DType;
//******************************************************************************
// Global var
//******************************************************************************

//******************************************************************************
// Local function prototype
//******************************************************************************
UCHAR rtp_H264_recive_init(void);
UCHAR RTPStop(void);
//******************************************************************************
// Macros
//******************************************************************************
#define BYTE2_SWAP(X) ((((short)(X) & 0xff00) >> 8) |(((short)(X) & 0x00ff) << 8))
#endif
//******************************************************************************
// ENF OF FILE
//******************************************************************************



video_H264_decode.c


//******************************************************************************
//include
//******************************************************************************
#include "main.h"
/*#include "video_H264_decode.h"
#include 
#include 
#include <chrono>
#include 

#pragma comment(lib, "ws2_32.lib")
#include */
#include <iostream>
#include <queue>

extern "C" {
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libpostproc/postprocess.h"
#include "libavcodec/avcodec.h"
}

#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avdevice.lib")
#pragma comment(lib,"avfilter.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"postproc.lib")
#pragma comment(lib,"swresample.lib")
#pragma comment(lib,"swscale.lib")

#pragma warning(disable: 4996)
//******************************************************************************
// Section for determining the variables used in the module
//******************************************************************************
//------------------------------------------------------------------------------
// Global
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Local
//------------------------------------------------------------------------------
const int inteval = 0x01000000;
BOOL FlagRTPActive = TRUE;

HANDLE hMutexRTPRecive;
HANDLE hSemaphoreRTP;
HANDLE hTreadRTPRecive;
HANDLE hTreadRTPDecode;


SOCKET RTPSocket; //socket UDP RTP
RTPData_DType packet;
RTPData_DType FU_buffer = { 0 };

std::queue q;
std::set<int> seq;

AVFormatContext* pAVFormatContext;
AVCodecContext* pAVCodecContext;
const AVCodec* pAVCodec;
AVFrame* pAVFrame;
AVFrame* AVFrameRGG;
SwsContext* pSwsContext;
AVPacket *pAVPacket;
AVCodecParserContext* pAVCodecParserContext;

UINT port;
//******************************************************************************
// Section of prototypes of local functions
//******************************************************************************
DWORD WINAPI rtp_H264_recive_Procedure(CONST LPVOID lpParam);
DWORD WINAPI rtp_decode_Procedure(CONST LPVOID lpParam);
char RTPSocketInit(void);
void RTPPacketParser(void);
char RTPSocketRecive(void);
void Decode_NaluToAVFrameRGG();
//******************************************************************************
// Section of the description of functions
//******************************************************************************
UCHAR rtp_H264_recive_init(void)
{
 hSemaphoreRTP = CreateSemaphore(
 NULL, // default security attributes
 0, // initial count
 1, // maximum count
 NULL); // unnamed semaphore

 hMutexRTPRecive = CreateMutex(
 NULL, // default security attributes
 FALSE, // initially not owned
 NULL); // unnamed mutex

 hTreadRTPRecive = CreateThread(NULL, NULL, rtp_H264_recive_Procedure, NULL, NULL, NULL);
 hTreadRTPDecode = CreateThread(NULL, NULL, rtp_decode_Procedure, NULL, NULL, NULL);

 return 0;
}
//------------------------------------------------------------------------------
UCHAR RTPStop(void)
{
 FlagRTPActive = FALSE;

 if (hSemaphoreRTP) CloseHandle(hSemaphoreRTP);
 if (hMutexRTPRecive) CloseHandle(hMutexRTPRecive);
 if (hTreadRTPRecive) CloseHandle(hTreadRTPRecive);

 closesocket(RTPSocket); 

 return 0;
}
//------------------------------------------------------------------------------
DWORD WINAPI rtp_H264_recive_Procedure(CONST LPVOID lpParam)
{
 while (RTPSocketInit() == 0)
 Sleep(2000);
 
 while (1)
 {
 RTPSocketRecive();
 RTPPacketParser();
 ReleaseSemaphore(hSemaphoreRTP, 1, NULL);
 }
}
//------------------------------------------------------------------------------
DWORD WINAPI rtp_decode_Procedure(CONST LPVOID lpParam)
{
 port = param.Option.VideoPort;

 pAVPacket = av_packet_alloc();
 if (!pAVPacket)
 {
 MessageBox(NULL, L"ERROR Could not allocate pAVPacket", L"Init decoder error", MB_OK | MB_ICONERROR);
 exit(1);
 }
 av_init_packet(pAVPacket);

 /* find the MPEG-1 video decoder */
 pAVCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
 if (!pAVCodec)
 {
 MessageBox(NULL, L"ERROR Codec not found", L"Init decoder error", MB_OK | MB_ICONERROR);
 exit(1);
 }

 pAVCodecParserContext = av_parser_init(pAVCodec->id);
 if (!pAVCodecParserContext)
 {
 MessageBox(NULL, L"ERROR Parser not found", L"Init decoder error", MB_OK | MB_ICONERROR);
 exit(1);
 }

 pAVCodecContext = avcodec_alloc_context3(pAVCodec);
 if (!pAVCodecContext) 
 {
 MessageBox(NULL, L"ERROR Could not allocate video codec context", L"Init decoder error", MB_OK | MB_ICONERROR);
 exit(1);
 }
 
 if (avcodec_open2(pAVCodecContext, pAVCodec, NULL) < 0)
 {
 MessageBox(NULL, L"ERROR Could not open codec", L"Init decoder error", MB_OK | MB_ICONERROR);
 exit(1);
 }

 pAVFrame = av_frame_alloc();
 if (!pAVFrame) 
 {
 MessageBox(NULL, L"ERROR Could not allocate video frame", L"Init decoder error", MB_OK | MB_ICONERROR);
 exit(1);
 } 
 
 while (FlagRTPActive)
 {
 if(port != param.Option.VideoPort)
 closesocket(RTPSocket);

 WaitForSingleObject(hSemaphoreRTP, 500); 
 Decode_NaluToAVFrameRGG();
 }

 avformat_free_context(pAVFormatContext);
 av_frame_free(&pAVFrame);
 avcodec_close(pAVCodecContext);
 av_packet_free(&pAVPacket);

 
 if (hTreadRTPDecode) CloseHandle(hTreadRTPDecode);

 return 0;
}

//------------------------------------------------------------------------------
char RTPSocketInit(void)
{ 
 sockaddr_in RTPSocketAddr;
 
 RTPSocketAddr.sin_family = AF_INET;
 RTPSocketAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 RTPSocketAddr.sin_port = htons(param.Option.VideoPort);

 RTPSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 if (RTPSocket == INVALID_SOCKET)
 {
 MessageBox(NULL, L"ERROR Invalid RTP Socket", L"UDP Socket", MB_OK | MB_ICONERROR);
 return 0;
 }

 int option = 12000;
 if (setsockopt(RTPSocket, SOL_SOCKET, SO_RCVBUF, (char*)&option, sizeof(option)) < 0)
 {
 printf("setsockopt failed\n");

 }

 /*option = TRUE;
 if (setsockopt(RTPSocket, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, (char*)&option, sizeof(option)) < 0)
 {
 printf("setsockopt failed\n");

 }*/

 if (bind(RTPSocket, (sockaddr*)&RTPSocketAddr, sizeof(RTPSocketAddr)) == SOCKET_ERROR)
 {
 MessageBox(NULL, L"ERROR bind", L"UDP Socket", MB_OK | MB_ICONERROR);
 closesocket(RTPSocket);
 return 0;
 }
 return 1;
}

//------------------------------------------------------------------------------
char RTPSocketRecive(void)
{
 static char RecvBuf[2000];
 static int BufLen = 2000;

 int iResult = 0;
 struct sockaddr_in SenderAddr;
 int SenderAddrSize = sizeof(SenderAddr);
 TCHAR szErrorMsg[100];

 iResult = recvfrom(RTPSocket, RecvBuf, BufLen, 0, NULL, NULL);
 if (iResult == SOCKET_ERROR && FlagRTPActive == TRUE)
 {
 StringCchPrintf(szErrorMsg, 100, L"ERROR recvfrom Ошибка:%d", WSAGetLastError());
 MessageBox(NULL, szErrorMsg, L"UDP Socket", MB_OK | MB_ICONERROR);
 return -1;
 }

 packet.data = (unsigned char*)RecvBuf;
 packet.size = iResult;

 return 1;
}

//------------------------------------------------------------------------------
void RTPPacketParser(void)
{
 RTPHeader_DType RTPHeader;
 RTPData_DType NALU;
 unsigned char* buffer = packet.data;
 int pos = 0;
 static int count = 0;
 static short lastSequenceNumber = 0xFFFF;
 short type;
 char payload_header;

 //read rtp header
 memcpy(&RTPHeader, buffer, sizeof(RTPHeader));
 RTPHeader.sequence_number = BYTE2_SWAP(RTPHeader.sequence_number);
 pos += 12; 
 
 if (RTPHeader.X) {
 //profile extension
 short define;
 short length;
 length = buffer[pos + 3];//suppose not so long extension
 pos += 4;
 pos += (length * 4);
 }

 payload_header = buffer[pos];
 type = payload_header & 0x1f; //Тип полезной нагрузки RTP
 pos++;
 
 //STAP-A
 if (type == 24)
 { 
 while (pos < packet.size)
 {
 unsigned short NALU_size;
 memcpy(&NALU_size, buffer + pos, 2);
 NALU_size = BYTE2_SWAP(NALU_size);
 pos += 2;
 char NAL_header = buffer[pos];
 short NAL_type = NAL_header & 0x1f;

 if (NAL_type == 7) 
 {
 count++;
 //cout<<"SPS, sequence number: "</cout<<"PPS, sequence number: "</cout<<"end of sequence, sequence number: "< 0) 
 {
 NALU.data = (unsigned char*) malloc(NALU_size + 4);
 NALU.size = NALU_size + 4;
 memcpy(NALU.data, &inteval, 4);
 memcpy(NALU.data + 4, &buffer[pos], NALU_size);

 WaitForSingleObject(hMutexRTPRecive, INFINITE);
 q.push(NALU);
 ReleaseMutex(hMutexRTPRecive);
 }

 pos += NALU_size;
 }
 }
 //FU-A Fragmentation unit
 else if (type == 28)
 { 
 //FU header
 char FU_header = buffer[pos];
 bool fStart = FU_header & 0x80;
 bool fEnd = FU_header & 0x40;

 //NAL header
 char NAL_header = (payload_header & 0xe0) | (FU_header & 0x1f);
 short NAL_type = FU_header & 0x1f;
 if (NAL_type == 7) 
 {
 count++;
 //SPS
 }
 else if (NAL_type == 8) 
 {
 //PPS
 }
 else if (NAL_type == 10) 
 {
 //end of sequence
 }
 pos++;

 int size = packet.size - pos;
 
 if (count > 0)
 {
 if (fStart) 
 {
 if (FU_buffer.size != 0)
 {
 free(FU_buffer.data);
 FU_buffer.size = 0;
 }
 FU_buffer.data = (unsigned char*)malloc(size + 5);
 if (FU_buffer.data == NULL)
 return;
 FU_buffer.size = size + 5;
 memcpy(FU_buffer.data, &inteval, 4);
 memcpy(FU_buffer.data + 4, &NAL_header, 1);
 memcpy(FU_buffer.data + 5, buffer + pos, size);
 }
 else
 {
 unsigned char* temp = (unsigned char*)malloc(FU_buffer.size + size);
 memcpy(temp, FU_buffer.data, FU_buffer.size);
 memcpy(temp + FU_buffer.size, buffer + pos, size);
 if (FU_buffer.size != 0) free(FU_buffer.data);
 FU_buffer.data = temp;
 FU_buffer.size += size;
 }

 if (fEnd)
 {
 NALU.data = (unsigned char*)malloc(FU_buffer.size);
 NALU.size = FU_buffer.size;
 memcpy(NALU.data, FU_buffer.data, FU_buffer.size);

 WaitForSingleObject(hMutexRTPRecive, INFINITE);
 q.push(NALU);
 ReleaseMutex(hMutexRTPRecive);

 free(FU_buffer.data);
 FU_buffer.size = 0;
 }
 }
 
 }
 else 
 {
 //other type
 short NAL_type = type;
 if (NAL_type == 7) 
 {
 count++;
 //SPS
 }
 else if (NAL_type == 8) 
 {
 //PPS
 }
 else if (NAL_type == 10) 
 {
 //end of sequence
 }

 int size = packet.size - pos + 1;
 if (count > 0)
 {
 NALU.data = (unsigned char*)malloc(size+4);
 NALU.size = size + 4;
 memcpy(NALU.data, &inteval, 4);
 memcpy(NALU.data + 4, &buffer[12], size);

 WaitForSingleObject(hMutexRTPRecive, INFINITE);
 q.push(NALU);
 ReleaseMutex(hMutexRTPRecive);
 }
 }
}

//------------------------------------------------------------------------------
void Decode_NaluToAVFrameRGG()
{
 unsigned char cntNALU;
 int len = 0;
 static int size = 0;
 unsigned char* data = NULL;
 int ret;
 RTPData_DType NALU;

 av_frame_unref(pAVFrame);
 av_packet_unref(pAVPacket);

 while(1)
 {
 WaitForSingleObject(hMutexRTPRecive, INFINITE);
 if (q.empty())
 {
 ReleaseMutex(hMutexRTPRecive);
 break;
 }
 NALU = q.front();
 q.pop();
 ReleaseMutex(hMutexRTPRecive);

 data = NALU.data;
 size = NALU.size;

 while(size)
 { 
 len = av_parser_parse2(pAVCodecParserContext, pAVCodecContext, &pAVPacket->data, &pAVPacket->size,
 (uint8_t*)data, size,
 AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);

 data = len ? data + len : data;
 size -= len;
 
 if (pAVPacket->size)
 {
 ret = avcodec_send_packet(pAVCodecContext, pAVPacket);

 if(ret == AVERROR_EOF)
 MessageBox(NULL, L"the codec has been fully flushed, and there will be no more output frames", L"avcodec_send_packet", MB_OK | MB_ICONERROR);

 if (ret < 0)
 {
 MessageBox(NULL, L"ERROR sending a packet for decoding", L"Decode", MB_OK | MB_ICONERROR);
 //exit(1);
 }

 while (ret >= 0) 
 {
 ret = avcodec_receive_frame(pAVCodecContext, pAVFrame);
 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
 break;
 else if (ret < 0) {
 MessageBox(NULL, L"ERROR during decoding", L"Decode", MB_OK | MB_ICONERROR);
 //exit(1);
 }
 
 AVFrameRGG = av_frame_alloc(); 
 pSwsContext = sws_getContext(pAVCodecContext->width, pAVCodecContext->height, pAVCodecContext->pix_fmt,
 pAVCodecContext->width, pAVCodecContext->height, AV_PIX_FMT_RGB24, SWS_SPLINE,
 0, 0, 0);

 sws_scale_frame(pSwsContext, AVFrameRGG, pAVFrame);
 
 ImgBufferSet(AVFrameRGG->data[0], pAVCodecContext->height, pAVCodecContext->width, AVFrameRGG->linesize[0]);

 sws_freeContext(pSwsContext);
 av_frame_free(&AVFrameRGG);
 }
 }
 }
 free(NALU.data);
 NALU.size = 0;
 } 
}

</int></queue></iostream></chrono>


It's DECIDED


-
Understanding Data Processing Agreements and How They Affect GDPR Compliance
9 octobre 2023, par Erin — GDPR -
Server Move For multimedia.cx
1er août 2014, par Multimedia Mike — GeneralI made a big change to multimedia.cx last week : I moved hosting from a shared web hosting plan that I had been using for 10 years to a dedicated virtual private server (VPS). In short, I now have no one to blame but myself for any server problems I experience from here on out.
The tipping point occurred a few months ago when my game music search engine kept breaking regardless of what technology I was using. First, I had an admittedly odd C-based CGI solution which broke due to mysterious binary compatibility issues, the sort that are bound to occur when trying to make a Linux binary run on heterogeneous distributions. The second solution was an SQLite-based solution. Like the first solution, this worked great until it didn’t work anymore. Something else mysteriously broke vis-à-vis PHP and SQLite on my server. I started investigating a MySQL-based full text search solution but couldn’t make it work, and decided that I shouldn’t have to either.
Ironically, just before I finished this entire move operation, I noticed that my SQLite-based FTS solution was working again on the old shared host. I’m not sure when that problem went away. No matter, I had already thrown the switch.
How Hard Could It Be ?
We all have thresholds for the type of chores we’re willing to put up with and which we’d rather pay someone else to perform. For the past 10 years, I felt that administering a website’s underlying software is something that I would rather pay someone else to worry about. To be fair, 10 years ago, I don’t think VPSs were a thing, or at least a viable thing in the consumer space, and I wouldn’t have been competent enough to properly administer one. Though I would have been a full-time Linux user for 5 years at that point, I was still the type to build all of my own packages from source (I may have still been running Linux From Scratch 10 years ago) which might not be the most tractable solution for server stability.These days, VPSs are a much more affordable option (easily competitive with shared web hosting). I also realized I know exactly how to install and configure all the software that runs the main components of the various multimedia.cx sites, having done it on local setups just to ensure that my automated backups would actually be useful in the event of catastrophe.
All I needed was the will to do it.
The Switchover Process
Here’s the rough plan :- Investigate options for both VPS providers and mail hosts– I might be willing to run a web server but NOT a mail server
- Start plotting several months in advance of my yearly shared hosting renewal date
- Screw around for several months, playing video games and generally finding reasons to put off the move
- Panic when realizing there are only a few days left before the yearly renewal comes due
So that’s the planning phase. BTW, I chose Digital Ocean for VPS and Zoho for email hosting. Here’s the execution phase I did last week :
- Register with Digital Ocean and set up DNS entries to point to the old shared host for the time being
- Once the D-O DNS servers respond correctly using a manual ‘dig’ command, use their servers as the authoritative ones for multimedia.cx
- Create a new Droplet (D-O VPS), install all the right software, move the databases, upload the files ; and exhaustively document each step, gotcha, and pitfall ; treat a VPS as necessarily disposable and have an eye towards iterating the process with a new VPS
- Use /etc/hosts on a local machine to point DNS to the new server and verify that each site is working correctly
- After everything looks all right, update the DNS records to point to the new server
Finally, flip the switch on the MX record by pointing it to the new email provider.
Improvements and Problems
Hosting on Digital Ocean is quite amazing so far. Maybe it’s the SSDs. Whatever it is, all the sites are performing far better than on the old shared web host. People who edit the MultimediaWiki report that changes get saved in less than the 10 or so seconds required on the old server.Again, all problems are now my problems. A sore spot with the shared web host was general poor performance. The hosting company would sometimes complain that my sites were using too much CPU. I would have loved to try to optimize things. However, the cPanel interface found on many shared hosts don’t give you a great deal of data for debugging performance problems. However, same sites, same software, same load on the VPS is considerably more performant.
Problem : I’ve already had the MySQL database die due to a spike in usage. I had to manually restart it. I was considering a cron-based solution to check if the server is running and restart it if not. In response to my analysis that my databases are mostly read and not often modified, so db crashes shouldn’t be too disastrous, a friend helpfully reminded me that, “You would not make a good sysadmin with attitudes like ‘an occasional crash is okay’.”
To this end, I am planning to migrate the database server to a separate VPS. This is a strategy that even Digital Ocean recommends. I’m hoping that the MySQL server isn’t subject to such memory spikes, but I’ll continue to monitor it after I set it up.
Overall, the server continues to get modest amounts of traffic. I predict it will remain that way unless Dark Shikari resurrects the x264dev blog. The biggest spike that multimedia.cx ever saw was when Steve Jobs linked to this WebM post.
Dropped Sites
There are a bunch of subdomains I dropped because I hadn’t done anything with them for years and I doubt anyone will notice they’re gone. One notable section that I decided to drop is the samples.mplayerhq.hu archive. It will live on, but it will be hosted by samples.ffmpeg.org, which had a full mirror anyway. The lower-end VPS instances don’t have the 53 GB necessary.Going Forward
Here’s to another 10 years of multimedia.cx, even if multimedia isn’t as exciting as it was 10 years ago (personal opinion ; I’ll have another post on this later). But at least I can get working on some other projects now that this is done. For the past 4 months or so, whenever I think of doing some other project, I always remembered that this server move took priority over everything else.