libyuv cra sh on iPhone - PullRequest
       23

libyuv cra sh on iPhone

1 голос
/ 07 января 2020

Я получил 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);
}

enter image description here

enter image description here

[Обновление от января / 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.

Я попробую их.

...