Я получил liberuv Cra sh недавно. Я очень стараюсь, но бесполезно. Пожалуйста, помогите или попробуйте дать некоторые идеи, как этого добиться. Спасибо!
У меня есть проект iOS ( Цель C). Одной из функций является кодирование видеопотока. Моя идея Шаг 1: Запустите таймер (20 кадров в секунду) Шаг 2. Скопируйте и получите растровые данные Шаг 3: Передайте данные растрового изображения в YUV I420 ( libyuv ) Шаг 4. Кодирование в формат h264 ( Openh264 ) Шаг 5. Отправьте данные h264 с помощью RTSP. Все функции работают на переднем плане.
Хорошо работает в течение 3 ~ 4 часов. НО это всегда будет падать после 4 часов +. Проверьте процессор (39%), память (140 МБ), она стабильна (нет утечки памяти, процессор занят и т. Д. c.). Я много пробую, но безуспешно (включите в свой проект add try-catch, определите размер данных перед запуском в этой строке) Я считаю, что он будет работать больше, если уменьшить время FPS (20FPS -> 15FPS) Нужно ли что-то добавлять после кодирования каждого кадра? Может ли кто-нибудь мне помочь или дать какую-нибудь идею для этого? Спасибо!
// This function runs in a GCD timer
- (void)processSDLFrame:(NSData *)_frameData {
if (mH264EncoderPtr == NULL) {
[self initEncoder];
return;
}
int argbSize = mMapWidth * mMapHeight * 4;
NSData *frameData = [[NSData alloc] initWithData:_frameData];
if ([frameData length] == 0 || [frameData length] != argbSize) {
NSLog(@"Incorrect frame with size : %ld\n", [frameData length]);
return;
}
SFrameBSInfo info;
memset(&info, 0, sizeof (SFrameBSInfo));
SSourcePicture pic;
memset(&pic, 0, sizeof (SSourcePicture));
pic.iPicWidth = mMapWidth;
pic.iPicHeight = mMapHeight;
pic.uiTimeStamp = [[NSDate date] timeIntervalSince1970];
@try {
libyuv::ConvertToI420(
static_cast<const uint8 *>([frameData bytes]), // sample
argbSize, // sample_size
mDstY, // dst_y
mStrideY, // dst_stride_y
mDstU, // dst_u
mStrideU, // dst_stride_u
mDstV, // dst_v
mStrideV, // dst_stride_v
0, // crop_x
0, // crop_y
mMapWidth, // src_width
mMapHeight, // src_height
mMapWidth, // crop_width
mMapHeight, // crop_height
libyuv::kRotateNone, // rotation
libyuv::FOURCC_ARGB); // fourcc
} @catch (NSException *exception) {
NSLog(@"libyuv::ConvertToI420 - exception:%@", exception.reason);
return;
}
pic.iColorFormat = videoFormatI420;
pic.iStride[0] = mStrideY;
pic.iStride[1] = mStrideU;
pic.iStride[2] = mStrideV;
pic.pData[0] = mDstY;
pic.pData[1] = mDstU;
pic.pData[2] = mDstV;
if (mH264EncoderPtr == NULL) {
NSLog(@"OpenH264Manager - encoder not initialized");
return;
}
int rv = -1;
@try {
rv = mH264EncoderPtr->EncodeFrame(&pic, &info);
} @catch (NSException *exception) {
NSLog( @"NSException caught - mH264EncoderPtr->EncodeFrame" );
NSLog( @"Name: %@", exception.name);
NSLog( @"Reason: %@", exception.reason );
[self deinitEncoder];
return;
}
if (rv != cmResultSuccess) {
NSLog(@"OpenH264Manager - encode failed : %d", rv);
[self deinitEncoder];
return;
}
if (info.eFrameType == videoFrameTypeSkip) {
NSLog(@"OpenH264Manager - drop skipped frame");
return;
}
// handle buffer data
int size = 0;
int layerSize[MAX_LAYER_NUM_OF_FRAME] = { 0 };
for (int layer = 0; layer < info.iLayerNum; layer++) {
for (int i = 0; i < info.sLayerInfo[layer].iNalCount; i++) {
layerSize[layer] += info.sLayerInfo[layer].pNalLengthInByte[i];
}
size += layerSize[layer];
}
uint8 *output = (uint8 *)malloc(size);
size = 0;
for (int layer = 0; layer < info.iLayerNum; layer++) {
memcpy(output + size, info.sLayerInfo[layer].pBsBuf, layerSize[layer]);
size += layerSize[layer];
}
// alloc new buffer for streaming
NSData *newData = [NSData dataWithBytes:output length:size];
// Send the data with RTSP
sendData( newData );
// free output buffer data
free(output);
}
[Обновление от января / 08/2020] Я сообщаю об этом тикете в Google Issue Report https://bugs.chromium.org/p/libyuv/issues/detail?id=853
Гуглер даст мне обратную связь.
ARGBToI420 does no allocations. Its similar to a memcpy with a source and destination and number of pixels to convert.
The most common issues with it are
1. the destination buffer has been deallocated. Try adding validation that the YUV buffer is valid. Write to the first and last byte of each layer.
This often occurs on shutdown and threads dont shut down in the order you were hoping. A mutex to guard the memory could help.
2. the destination is an odd size and the allocator did not allocate enough memory. When alllocating the UV plane, use (width + 1) / 2 for width/stride and (height + 1) / 2 for height of UV. Allocate stride * height bytes. You could also use an allocator that verifies there are no overreads or overwrites, or a sanitizer like asan / msan.
When screen casting, usually windows are a multiple of 2 pixels on Windows and Linux, but I have seen MacOS use odd pixel count.
As a test you could wrap the function with temporary buffers. Copy the ARGB to a temporary ARGB buffer.
Call ARGBToI420 to a temporary I420 buffer.
Copy the I420 result to the final I420 buffer.
That should give you a clue which buffer/function is failing.
Я попробую их.