Слияние кода завершено, страница обновится автоматически
2023-12-25 [rtsp, rtmp, поддержка ГОСТ GB28181 в режиме чистого аудио, то есть без видео, параметры видео установлены как VideoCodec_NONE]
1. Обновлен медиа-сервер Beijing-Лао Чен
2023-12-20 [rtsp, rtmp, поддержка ГОСТ GB28181 в режиме чистого аудио, то есть без видео, параметры видео установлены как VideoCodec_NONE]
1. Обновлен сетевой модуль на асинхронную версию
2023-07-15 [rtsp, rtmp, поддержка ГОСТ GB28181 в режиме чистого аудио, то есть без видео, параметры видео установлены как VideoCodec_NONE]
1. Добавлены сборки для платформы ARM
arm_bin уже собраны, включают SDK, rtsp\rtmp\ГОСТ GB28181 примеры вызова потоков
\SDK\arm уже собраны, ABLPush потоковый библиотека SDK
\example\arm\rtspDemo пример вызова потоковой библиотеки на платформе ARM. Процесс включает получение 1 потока rtsp, затем отправку rtsp, rtmp, ГОСТ GB28181
\media-server-master\arm_lib статические библиотеки медиа-сервера для платформы ARM, уже собраны
2023-07-08 [rtsp, rtmp, поддержка ГОСТ GB28181 в режиме чистого аудио, то есть без видео, параметры видео установлены как VideoCodec_NONE]
1. Обновлен медиа-сервер до последней версии, и livflv настроен на компиляцию с макросом FLV_ENHANCE_RTMP для rtmp\flv 265
2023-02-06 [rtsp, rtmp, поддержка ГОСТ GB28181 в режиме чистого аудио, то есть без видео, параметры видео установлены как VideoCodec_NONE]
1. Поддержка сигналов для пула потоков сетевого приема CNetBaseThreadPool и пула потоков сетевого отправления CMediaSendThreadPool
1. ) Определение сигналов
std::condition_variable cv[MaxMediaSendThreadCount];
std::mutex mtx[MaxMediaSendThreadCount];
2. ) Уведомление сигналов при добавлении задач
bool CNetBaseThreadPool::InsertIntoTask(uint64_t nClientID)
{
std::lock_guard<std::mutex> lock(threadLock);
int nThreadThread = 0;
ClientProcessThreadMap::iterator it;
it = clientThreadMap.find(nClientID);
if (it != clientThreadMap.end())
{// найдено
nThreadThread = (*it).second;
}
else
{// еще не добавлено
nThreadThread = nThreadProcessCount % nTrueNetThreadPoolCount;
clientThreadMap.insert(ClientProcessThreadMap::value_type(nClientID, nThreadThread));
nThreadProcessCount ++;
} m_NetHandleQueue[nThreadThread].push(nClientID);
cv[nThreadThread].notify_one();
return true;
}
3. При отсутствии данных при сетевом приеме, устанавливаем состояние ожидания для потока.
void CNetBaseThreadPool::ProcessFunc()
{
int nCurrentThreadID = nGetCurrentThreadOrder;
bExitProcessThreadFlag[nCurrentThreadID] = false;
uint64_t nClientID; bCreateThreadFlag = true; //creation of the thread completed
while (bRunFlag)
{
if (m_NetHandleQueue[nCurrentThreadID].pop(nClientID) && bRunFlag)
{
boost::shared_ptr<CNetRevcBase> pClient = GetNetRevcBaseClient(nClientID);
if (pClient != NULL)
{
pClient->ProcessNetData(); //processing the task
}
}
else
{
if (bRunFlag)
{
std::unique_lock<std::mutex> lck(mtx[nCurrentThreadID]);
cv[nCurrentThreadID].wait(lck);
}
else
break;
}
}
bExitProcessThreadFlag[nCurrentThreadID] = true;
}
2023-01-30
1. Fixing the handshake notification upon successful connection when only audio is sent
nRecvDataTimerBySecond = 0;
if (bHandshakeFlag == false && netBaseNetType == NetBaseNetType_NetGB28181SendRtpUDP)
{//UDP, if only binding, is considered a successful handshake
WriteLog(Log_Debug, " nClient = %llu ,url = %s successfully connected to the server! Now you can send the stream ", nClient, szClientIP);
bHandshakeFlag = true; //indicates successful interaction
calllBack.iEvent = ABLPush_STATE_PUSHING;
pCallBackFifo.push((unsigned char*)&calllBack, sizeof(CallBackParam));
}
2023-01-28
1. Adding support for PS-packetization library from Beijing Lao Chen
//use our own implementation of PS-packetization
#ifdef UseSelfPsPacketFlag
psMuxHandle = 0;
#else //use PS-packetization from Beijing Lao Chen
nVideoStreamID = nAudioStreamID = -1;
handler.alloc = ps_alloc;
handler.write = ps_write;
handler.free = ps_free;
videoPTS = audioPTS = 0;
ps = ps_muxer_create(&handler, this);
#endif
//PS-packetization
#ifdef UseSelfPsPacketFlag
input.mediatype = e_psmux_mt_video;
if (m_mediaCodeInfo.videoType == VideoCodec_H264 )
input.streamtype = e_psmux_st_h264;
else if (m_mediaCodeInfo.videoType == VideoCodec_H265)
input.streamtype = e_psmux_st_h265;
else
{
m_videoFifo.pop_front();
return 0;
} input.data = pData;
input.datasize = nLength;
ps_mux_input(&input);
#else
if (nVideoStreamID != -1 && ps != NULL && m_mediaCodeInfo.videoType != VideoCodec_NONE)
{
if(m_mediaCodeInfo.videoType == VideoCodec_H264)
nflags = CheckVideoIsIFrame("H264", pData, nLength);
else
nflags = CheckVideoIsIFrame("H265", pData, nLength);
ps_muxer_input((ps_muxer_t*)ps, nVideoStreamID, nflags, videoPTS, videoPTS, pData, nLength);
videoPTS += (90000 / m_mediaCodeInfo.nVideoFrameRate);
#endif
2023-01-26
1. Поддержка только аудио потока
if (m_mediaCodeInfo.audioType == AudioCodec_G711A)
{
optionAudio.ttincre = 320; //длина увеличения для G711A
optionAudio.streamtype = e_rtppkt_st_g711a;
nAudioPayload = 8;
if (m_mediaCodeInfo.videoType != VideoCodec_NONE) //есть видео и аудио
sprintf(szRtspAudioSDP, "m=audio 0 RTP/AVP %d\r\nb=AS:50\r\na=recvonly\r\na=rtpmap:%d PCMA/%d\r\na=control:streamid=1\r\na=framerate:25\r\n", nAudioPayload, nAudioPayload, 8000);
else //только аудио
sprintf(szRtspAudioSDP, "m=audio 0 RTP/AVP %d\r\nb=AS:50\r\na=recvonly\r\na=rtpmap:%d PCMA/%d\r\na=control:streamid=0\r\na=framerate:25\r\n", nAudioPayload, nAudioPayload, 8000);
nMediaCount++;
}
else if (m_mediaCodeInfo.audioType == AudioCodec_G711U)
{
optionAudio.ttincre = 320; //длина увеличения для G711U
optionAudio.streamtype = e_rtppkt_st_g711u;
nAudioPayload = 0;
if (m_mediaCodeInfo.videoType != VideoCodec_NONE) //есть видео и аудио
sprintf(szRtspAudioSDP, "m=audio 0 RTP/AVP %d\r\nb=AS:50\r\na=recvonly\r\na=rtpmap:%d PCMU/%d\r\na=control:streamid=1\r\na=framerate:25\r\n", nAudioPayload, nAudioPayload, 8000);
else //только аудио
sprintf(szRtspAudioSDP, "m=audio 0 RTP/AVP %d\r\nb=AS:50\r\na=recvonly\r\na=rtpmap:%d PCMU/%d\r\na=control:streamid=0\r\na=framerate:25\r\n", nAudioPayload, nAudioPayload, 8000);```c
nMediaCount++;
}
else if (m_mediaCodeInfo.audioType == AudioCodec_AAC || m_mediaCodeInfo.audioType == AudioCodec_G711AtoAAC || m_mediaCodeInfo.audioType == AudioCodec_G711UtoAAC)
{
optionAudio.ttincre = 1024 ;//длина увеличения для AAC
optionAudio.streamtype = e_rtppkt_st_aac;
nAudioPayload = 104;
}
``````c
if (m_mediaCodeInfo.videoType != VideoCodec_NONE) // Есть видео, аудио
sprintf(szRtspAudioSDP, "m=audio 0 RTP/AVP %d\r\na=rtpmap:%d MPEG4-GENERIC/%d/%d\r\na=fmtp:%d profile-level-id=15; streamtype=5; mode=AAC-hbr; config=1408;SizeLength=13; IndexLength=3; IndexDeltaLength=3; Profile=1;\r\na=control:streamid=1\r\n", nAudioPayload, nAudioPayload, m_mediaCodeInfo.nSampleRate, m_mediaCodeInfo.nChannels, nAudioPayload);
else // Только аудио
sprintf(szRtspAudioSDP, "m=audio 0 RTP/AVP %d\r\na=rtpmap:%d MPEG4-GENERIC/%d/%d\r\na=fmtp:%d profile-level-id=15; streamtype=5; mode=AAC-hbr; config=1408;SizeLength=13; IndexLength=3; IndexDeltaLength=3; Profile=1;\r\na=control:streamid=0\r\n", nAudioPayload, nAudioPayload, m_mediaCodeInfo.nSampleRate, m_mediaCodeInfo.nChannels, nAudioPayload);
``````c
nMediaCount++;
}
```
Исправленный текст:
```c
nMediaCount++;
}
else if (m_mediaCodeInfo.audioType == AudioCodec_AAC || m_mediaCodeInfo.audioType == AudioCodec_G711AtoAAC || m_mediaCodeInfo.audioType == AudioCodec_G711UtoAAC)
{
optionAudio.ttincre = 1024; // длина увеличения для AAC
optionAudio.streamtype = e_rtppkt_st_aac;
nAudioPayload = 104;
}
``````c
if (m_mediaCodeInfo.videoType != VideoCodec_NONE) // Есть видео, аудио
sprintf(szRtspAudioSDP, "m=audio 0 RTP/AVP %d\r\na=rtpmap:%d MPEG4-GENERIC/%d/%d\r\na=fmtp:%d profile-level-id=15; streamtype=5; mode=AAC-hbr; config=1408;SizeLength=13; IndexLength=3; IndexDeltaLength=3; Profile=1;\r\na=control:streamid=1\r\n", nAudioPayload, nAudioPayload, m_mediaCodeInfo.nSampleRate, m_mediaCodeInfo.nChannels, nAudioPayload);
else // Только аудио
sprintf(szRtspAudioSDP, "m=audio 0 RTP/AVP %d\r\na=rtpmap:%d MPEG4-GENERIC/%d/%d\r\na=fmtp:%d profile-level-id=15; streamtype=5; mode=AAC-hbr; config=1408;SizeLength=13; IndexLength=3; IndexDeltaLength=3; Profile=1;\r\na=control:streamid=0\r\n", nAudioPayload, nAudioPayload, m_mediaCodeInfo.nSampleRate, m_mediaCodeInfo.nChannels, nAudioPayload);
``````c
nMediaCount++;
}
```2. Если есть только звук, не накапливайте звуковые данные, а отправьте их сразу
void CNetClientSendRtsp::ProcessRtpAudioData(unsigned char* pRtpAudio, int nDataLength)
{
if (m_mediaCodeInfo.videoType != VideoCodec_NONE)
{
if ((MaxRtpSendAudioMediaBufferLength - nSendRtpAudioMediaBufferLength < nDataLength + 4) && nSendRtpAudioMediaBufferLength > 0)
{//остаточное пространство недостаточно для хранения, предотвращаем ошибки
SumSendRtpMediaBuffer(szSendRtpAudioMediaBuffer, nSendRtpAudioMediaBufferLength);
nSendRtpAudioMediaBufferLength = 0;
nCalcAudioFrameCount = 0;
}
szSendRtpAudioMediaBuffer[nSendRtpAudioMediaBufferLength + 0] = '$';
szSendRtpAudioMediaBuffer[nSendRtpAudioMediaBufferLength + 1] = 2;
nAudioRtpLen = htons(nDataLength);
memcpy(szSendRtpAudioMediaBuffer + (nSendRtpAudioMediaBufferLength + 2), (unsigned char*)&nAudioRtpLen, sizeof(nAudioRtpLen));
memcpy(szSendRtpAudioMediaBuffer + (nSendRtpAudioMediaBufferLength + 4), pRtpAudio, nDataLength);
nSendRtpAudioMediaBufferLength += nDataLength + 4;
nCalcAudioFrameCount++;
if (nCalcAudioFrameCount >= 3 && nSendRtpAudioMediaBufferLength > 0)
{
SumSendRtpMediaBuffer(szSendRtpAudioMediaBuffer, nSendRtpAudioMediaBufferLength);
nSendRtpAudioMediaBufferLength = 0;
nCalcAudioFrameCount = 0;
}
}
else
{//отправляем только аудио
nSendRtpAudioMediaBufferLength = 0;
szSendRtpAudioMediaBuffer[nSendRtpAudioMediaBufferLength + 0] = '$';
szSendRtpAudioMediaBuffer[nSendRtpAudioMediaBufferLength + 1] = 0;```cpp
nAudioRtpLen = htons(nDataLength);
memcpy(szSendRtpAudioMediaBuffer + (nSendRtpAudioMediaBufferLength + 2), (unsigned char*)&nAudioRtpLen, sizeof(nAudioRtpLen));
memcpy(szSendRtpAudioMediaBuffer + (nSendRtpAudioMediaBufferLength + 4), pRtpAudio, nDataLength);
XHNetSDK_Write(nClient, szSendRtpAudioMediaBuffer, nDataLength + 4, 1);
}
}
```2022-12-31
1. Видео и аудио не могут быть одновременно NULL
if (videoType == VideoCodec_NONE && audioType == AudioCodec_NONE)
return ABLPush_ErrorCode_VideoAudioIsNull;
2. Удалить проверку аудио формата при использовании rtmp, чтобы избежать ошибки при создании ручки для rtmp-потока
if (memcmp(szURL, "rtmp://", 7) == 0 && (audioType == AudioCodec_G711A || audioType == AudioCodec_G711U || audioType == AudioCodec_AACtoG711A || audioType == AudioCodec_AACtoG711U))
return ABLPush_ErrorCode_UnsupportAudio;
3. При отправке rtmp, для аудио AAC требуется добавить условие проверки
int CNetClientSendRtmp::PushAudio(uint8_t* pAudioData, uint32_t nDataLength, char* szAudioCodec, int nChannels, int SampleRate)
{
if (!bRunFlag || !bAddThreadPoolFlag) // rtmp-сессия завершена, прежде чем отправлять
return -1;
if (m_mediaCodeInfo.audioType == AudioCodec_G711AtoAAC || m_mediaCodeInfo.audioType == AudioCodec_G711UtoAAC)
{
if (aacEnc.hEncoder == NULL)
aacEnc.InitAACEncodec(64000, 8000, 1, &nAACEncodeLength);
if (ConvertG711ToAAC(m_mediaCodeInfo.audioType, pAudioData, nDataLength, pOutAACData, nOutAACDataLength) == false)
return false;
}
}
```cpp
// Преобразование G711 в AAC
if (m_mediaCodeInfo.audioType == AudioCodec_G711AtoAAC || m_mediaCodeInfo.audioType == AudioCodec_G711UtoAAC)
{
if (aacEnc.hEncoder == NULL)
aacEnc.InitAACEncodec(64000, 8000, 1, &nAACEncodeLength);
if (ConvertG711ToAAC(m_mediaCodeInfo.audioType, pAudioData, nDataLength, pOutAACData, nOutAACDataLength) == false)
return false;
}
``` m_audioFifo.push(pOutAACData, nOutAACDataLength);
}
else if (m_mediaCodeInfo.audioType == AudioCodec_AAC) // Не требуется кодирование
m_audioFifo.push(pAudioData, nDataLength);
return 0;
}
2022-12-23
1. Проверка ssrc/src_port на наличие в использовании
int CheckSSRC_SRC_Port(char* ssrc, char* src_port)
{
std::lock_guard<std::mutex> lock(ABL_CNetRevcBase_ptrMapLock);
CNetRevcBase_ptrMap::iterator iterator1;
for (iterator1 = xh_ABLNetRevcBaseMap.begin(); iterator1 != xh_ABLNetRevcBaseMap.end(); ++iterator1)
{
if (atoi(ssrc) != 0 && strcmp((*iterator1).second->gb28181PushStruct.ssrc, ssrc) == 0)
return ABLPush_ErrorCode_SsrcIdentical;
else if (atoi(src_port) != 0 && strcmp((*iterator1).second->gb28181PushStruct.src_port, src_port) == 0)
return ABLPush_ErrorCode_Ssrc_PortIdentical;
}
return 0; // Отсутствие дубликатов
}
2. Поддержка преобразования G711A и G711U в AAC при отправке стандартного потока
1) Выполнение преобразования
if (m_mediaCodeInfo.audioType == AudioCodec_G711AtoAAC || m_mediaCodeInfo.audioType == AudioCodec_G711UtoAAC)
{
if (aacEnc.hEncoder == NULL)
aacEnc.InitAACEncodec(64000, 8000, 1, &nAACEncodeLength);
if (ConvertG711ToAAC(m_mediaCodeInfo.audioType, pAudioData, nDataLength, pOutAACData, nOutAACDataLength) == false)
return false;
m_audioFifo.push(pOutAACData, nOutAACDataLength);
}
else // Не требуется кодирование
m_audioFifo.push(pAudioData, nDataLength);
2) Изменение формата аудиокодирования при упаковке стандартного потока
else if (m_mediaCodeInfo.audioType == AudioCodec_G711AtoAAC)
input.streamtype = e_psmux_st_aac;
else if (m_mediaCodeInfo.audioType == AudioCodec_G711UtoAAC)
input.streamtype = e_psmux_st_aac;3. Добавление двух параметров ssrc и src_port для ошибок и проверки
ABLPush_ErrorCode_SsrcIdentical = -10; // SSRC повторяется, должен быть уникальным
ABLPush_ErrorCode_Ssrc_PortIdentical = -11; // src_port повторяется, должен быть уникальным
```
// Проверка ssrc, src_port
if (memcmp(szURL, "rtp://", 6) == 0)
{
char szSSRC[256] = { 0 };
char szSrc_Port[256] = { 0 };
strcpy(szSSRC, "0");
strcpy(szSrc_Port, "0");
string strURL = szURL;
int nPos1, nPos2;
nPos1 = strURL.find("ssrc=", 0);
if (nPos1 > 0)
{
nPos2 = strURL.find("&", nPos1 + 1);
if (nPos2 > nPos1)
memcpy(szSSRC, szURL + nPos1 + 5, nPos2 - nPos1 - 5);
else
memcpy(szSSRC, szURL + nPos1 + 5, strlen(szURL) - nPos1 - 5);
}
nPos1 = strURL.find("src_port=", 0);
if (nPos1 > 0)
{
nPos2 = strURL.find("&", nPos1 + 1);
if (nPos2 > nPos1)
memcpy(szSrc_Port, szURL + nPos1 + 9, nPos2 - nPos1 - 9);
else
memcpy(szSrc_Port, szURL + nPos1 + 9, strlen(szURL) - nPos1 - 9);
}
}
// Проверка, что оба параметра заняты
int nCheck = CheckSSRC_SRC_Port(szSSRC, szSrc_Port);
if (nCheck != 0)
return nCheck;
```2022-12-22
1. Объединение кода для проверки md5 на платформах Linux и Windows в один версионный файл
2. Добавление поддержки国家标准推流 NetGB28181RtpClient.cpp NetGB28181RtpClient.h
2022-12-21
1. Перенос на платформу Linux
2022-12-13
1. Добавление кодирования G711A и G711U в AAC
bool CNetRevcBase::ConvertG711ToAAC(int nCodec, unsigned char* pG711, int nBytes, unsigned char* szOutAAC, int& nAACLength)
{
if (pG711 == NULL || nBytes <= 0)
return false;
bool bRet = false;
if (nBytes < 320)
{// Необходимо склеить
memcpy(g711CacheBuffer + nG711CacheLength, pG711, nBytes);
nG711CacheLength += nBytes;
if (nG711CacheLength < 320)
return false;
}
if (nCodec == AudioCodec_G711AtoAAC)
{
if (nBytes < 320)
alaw_to_pcm16(320, (const char*)g711CacheBuffer, g711toPCM);
else
alaw_to_pcm16(320, (const char*)pG711, g711toPCM);
}
else if (nCodec == AudioCodec_G711UtoAAC)
{
if (nBytes < 320)
ulaw_to_pcm16(320, (const char*)g711CacheBuffer, g711toPCM);
else
ulaw_to_pcm16(320, (const char*)pG711, g711toPCM);
}
else
return false;
// Необходимо склеить
if (nBytes < 320)
nG711CacheLength -= 320;
if (1024 * 16 - nG711ToPCMCacheLength > 640)
{
memcpy(g711ToPCMCache + nG711ToPCMCacheLength, g711toPCM, 640);
nG711ToPCMCacheLength += 640;
}
if (nG711ToPCMCacheLength >= nAACEncodeLength)
{
memcpy(aacEnc.pbPCMBuffer, g711ToPCMCache, nAACEncodeLength);
aacEnc.EncodecAAC(&nRetunEncodeLength);
if (nRetunEncodeLength > 0)
{
memcpy(szOutAAC, (unsigned char*)aacEnc.pbAACBuffer, nRetunEncodeLength);
nAACLength = nRetunEncodeLength;
bRet = true;
}
memmove(g711ToPCMCache, g711ToPCMCache + nAACEncodeLength, nG711ToPCMCacheLength - nAACEncodeLength);
nG711ToPCMCacheLength = nG711ToPCMCacheLength - nAACEncodeLength;
#ifdef WriteEncodeAACFlag
if (fWriteAACFile && nAACLength > 0)
{
fwrite(szOutAAC, 1, nAACLength, fWriteAACFile);
fflush(fWriteAACFile);
}
#endif
return bRet;
}
else
return false; // недостаточно для AAC аудио длины
}2. Поддержка rtsp потока с кодированием G711U и G711A в AAC
int CNetClientSendRtsp::PushAudio(uint8_t* pAudioData, uint32_t nDataLength, char* szAudioCodec, int nChannels, int SampleRate)
{
if (!bRunFlag || !bHandshakeFlag)
return -1;
}
// Преобразование G711 в AAC
if (m_mediaCodeInfo.audioType == AudioCodec_G711AtoAAC || m_mediaCodeInfo.audioType == AudioCodec_G711UtoAAC)
{
if (aacEnc.hEncoder == NULL)
aacEnc.InitAACEncodec(64000, 8000, 1, &nAACEncodeLength);
if (ConvertG711ToAAC(m_mediaCodeInfo.audioType, pAudioData, nDataLength, pOutAACData, nOutAACDataLength) == false)
return false;
m_audioFifo.push(pOutAACData, nOutAACDataLength);
}
else // Не преобразовывать
m_audioFifo.push(pAudioData, nDataLength);
return 0;
}
```cpp
// Преобразование G711 в AAC для RTMP
int CNetClientSendRtmp::PushAudio(uint8_t* pAudioData, uint32_t nDataLength, char* szAudioCodec, int nChannels, int SampleRate)
{
if (!bRunFlag || !bAddThreadPoolFlag) // RTMP сессия завершена
return -1;
// Преобразование G711 в AAC
if (m_mediaCodeInfo.audioType == AudioCodec_G711AtoAAC || m_mediaCodeInfo.audioType == AudioCodec_G711UtoAAC)
{
if (aacEnc.hEncoder == NULL)
aacEnc.InitAACEncodec(64000, 8000, 1, &nAACEncodeLength);
if (ConvertG711ToAAC(m_mediaCodeInfo.audioType, pAudioData, nDataLength, pOutAACData, nOutAACDataLength) == false)
return false;
m_audioFifo.push(pOutAACData, nOutAACDataLength);
}
else // Не преобразовывать
m_audioFifo.push(pAudioData, nDataLength);
return 0;
}
```
```text
2022-12-04
1. Добавлены все события для RTSP-потока.
2. Примеры вызова поддерживают RTSP и RTMP-потоки.
3. Исправлены примеры вызова для отправки потока.
2022-12-03
1. Добавлен RTSP-поток.
2. Добавлены логи.
2022-12-02
1. Проект только создан.
2. Поддерживается отправка видео H264 и H265.
3. Завершены уведомления событий.
```
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )