Qt desarrollo de audio y video 18-haikang sdk callback

I. Introducción

Haikang sdk muestra transmisiones de video en tiempo real además del método de control, y también admite el método de devolución de llamada para que cada imagen se dibuje y procese. Por supuesto, el método de devolución de llamada no es solo para obtener los datos de video, sino que los datos de audio también se obtienen juntos. Simplemente llame al dispositivo de audio para reproducirlos. , Con respecto a la devolución de llamada SDK de Haikang, me tomó un tiempo hacerlo. Tal vez no me referí a la demostración proporcionada al principio y no busqué a fondo. Solo miré el documento SDK para lanzar y lanzar, y fue una semana. No lo entendí. Encontré el camino correcto más tarde, pero casi lo pierdo. Esto me recuerda muchas cosas, incluidas cosas de la vida. ¿No es cierto? Cuando eres lo suficientemente terco, experimentas con varios métodos, y estás casi agotado para rendirte, de hecho, estás a un paso del éxito en este momento y realmente estás muy perdido. Lo mismo ocurre con el manejo de muchas cosas en la vida. Entonces, en muchos casos, si la dirección es la correcta, y si persistió y trabajó duro, si no funciona, esfuércese más y estime que estará bien.

Ha pasado mucho tiempo para resumir dónde está la falla. Llamar a NET_DVR_RealPlay_V40 para configurar la función de devolución de llamada también es correcto, y la función de devolución de llamada también se ingresó. También es correcto llamar a PlayM4_SetDecCallBackMend para configurar la función de devolución de llamada de decodificación. Al final, descubrí que el problema radica en los datos decodificados, y los datos también se obtienen. El valor predeterminado son los datos yv12. Si necesita convertir a imagen, debe hacer una conversión. Esta conversión en línea encuentra un montón de funciones Vine a la prueba, pero todos fallaron. Más tarde, encontré un formato yv12 a rgb888, y finalmente fue posible, así que fui.

Proceso de devolución de llamada del SDK de Haikang:

  1. Llame a NET_DVR_RealPlay_V40 para configurar la función de procesamiento de devolución de llamada.
  2. Abra, reproduzca y decodifique secuencialmente en la función de procesamiento de devolución de llamada RealDataCallBack.
  3. Llame a PlayM4_GetPort para obtener el número de canal no utilizado de la biblioteca de reproducción.
  4. Llame a PlayM4_OpenStream para abrir la transmisión de video.
  5. Llame a PlayM4_SetDecCallBackMend para configurar la función de devolución de llamada de decodificación, solo decodifica pero no muestra.
  6. Llame a PlayM4_Play para reproducir la transmisión de video.
  7. Llame a PlayM4_InputData para decodificar los datos de forma cíclica.
  8. Los datos de audio y video se procesan por separado en la función de devolución de llamada de decodificación DecCallBack.
  9. Llame a la función yv12ToRGB888 empaquetada por usted mismo para convertir los datos en QImage.

Tenga en cuenta los siguientes puntos sobre la función de devolución de llamada:

  1. La función de devolución de llamada debe tener la palabra clave CALLBACK.
  2. La función de devolución de llamada en sí debe ser una función global o una función estática, y no se puede definir como una función miembro de una clase en particular.
  3. El desarrollador no llama ni ejecuta directamente la función de devolución de llamada, sino que utiliza la función API de la interfaz del sistema como punto de partida.
  4. La función de devolución de llamada generalmente se pasa como un parámetro a la API del sistema y la API la llama.
  5. La función de devolución de llamada puede ser llamada una vez por la API del sistema, o puede ser llamada varias veces en un ciclo.

2. Características

  1. Admite la reproducción de secuencias de video y archivos MP4 locales.
  2. Admite dos modos: manejo y devolución de llamada.
  3. Imágenes de pantalla multiproceso, no atascadas en la interfaz principal.
  4. Vuelva a conectar la cámara web automáticamente.
  5. Puede establecer el tamaño del borde, el desplazamiento y el color del borde.
  6. Puede establecer si desea dibujar etiquetas OSD, es decir, etiquetar texto o imágenes y posiciones de etiquetas.
  7. Se pueden configurar dos posiciones y estilos de OSD.
  8. Puede establecer si guardar en archivo y nombre de archivo.
  9. Puede arrastrar archivos directamente al control de haikangwidget para reproducirlos.
  10. Admite transmisión de video h264 / h265.
  11. Puede pausar y reanudar la reproducción.
  12. Admite el almacenamiento de archivos de video individuales y el almacenamiento de tiempo de archivos de video.
  13. Personalice la barra flotante superior, envíe una notificación de señal de clic y establezca si desea habilitarla.
  14. Puede establecer el relleno de estiramiento de la pantalla o el relleno de igual proporción.
  15. Puede configurar la decodificación para que tenga prioridad de velocidad, prioridad de calidad y procesamiento de ecualización.
  16. Puede tomar capturas de pantalla (imágenes originales) y capturas de pantalla (formas de video) de videos.
  17. Los archivos de video se almacenan como archivos MP4.
  18. Admite control de enfoque, control de panorámica / inclinación.
  19. Funciones personalizables.

Tres, representaciones

Inserte la descripción de la imagen aquí

Cuatro sitios relacionados

  1. Sitio nacional: https://gitee.com/feiyangqingyun/QWidgetDemo
  2. Sitio internacional: https://github.com/feiyangqingyun/QWidgetDemo
  3. Página de inicio personal: https://blog.csdn.net/feiyangqingyun
  4. Página de inicio de Zhihu: https://www.zhihu.com/people/feiyangqingyun/
  5. Dirección de experiencia: https://blog.csdn.net/feiyangqingyun/article/details/97565652

Cinco, el código central

//yv12转RGB888
static bool yv12ToRGB888(const unsigned char *yv12, unsigned char *rgb888, int width, int height)
{
    if ((width < 1) || (height < 1) || (yv12 == NULL) || (rgb888 == NULL)) {
        return false;
    }

    int len = width * height;
    unsigned char const *yData = yv12;
    unsigned char const *vData = &yData[len];
    unsigned char const *uData = &vData[len >> 2];

    int rgb[3];
    int yIdx, uIdx, vIdx, idx;

    for (int i = 0; i < height; ++i) {
        for (int j = 0; j < width; ++j) {
            yIdx = i * width + j;
            vIdx = (i / 2) * (width / 2) + (j / 2);
            uIdx = vIdx;

            rgb[0] = static_cast<int>(yData[yIdx] + 1.370705 * (vData[uIdx] - 128));
            rgb[1] = static_cast<int>(yData[yIdx] - 0.698001 * (uData[uIdx] - 128) - 0.703125 * (vData[vIdx] - 128));
            rgb[2] = static_cast<int>(yData[yIdx] + 1.732446 * (uData[vIdx] - 128));

            for (int k = 0; k < 3; ++k) {
                idx = (i * width + j) * 3 + k;
                if ((rgb[k] >= 0) && (rgb[k] <= 255)) {
                    rgb888[idx] = static_cast<unsigned char>(rgb[k]);
                } else {
                    rgb888[idx] = (rgb[k] < 0) ? (0) : (255);
                }
            }
        }
    }
    return true;
}

//解码回调 视频为YUV420P数据(YV12),音频为PCM数据
static void CALLBACK DecCallBack(qport nPort, char *pBuf, qport nSize, FRAME_INFO *pFrameInfo, quser luser, quser nReserved2)
{
    HaiKangThread *thread = (HaiKangThread *)luser;
    long frameType = pFrameInfo->nType;

    //视频数据是 T_YV12 音频数据是 T_AUDIO16
    if (frameType == T_YV12) {
        //qDebug() << TIMEMS << width << height << thread;
        int width = pFrameInfo->nWidth;
        int height = pFrameInfo->nHeight;
        QImage image(width, height, QImage::Format_RGB888);
        if (yv12ToRGB888((unsigned char *)pBuf, image.bits(), width, height)) {
            thread->setImage(image);
        }
    } else if (frameType == T_AUDIO16) {
        //qDebug() << TIMEMS << "T_AUDIO16" << thread;
    }
}

static void CALLBACK RealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *dwUser)
{
    //每个类都对应自己的 port
    HaiKangThread *thread = (HaiKangThread *)dwUser;
    qport nPort = thread->port;

    DWORD dRet;
    switch (dwDataType) {
        case NET_DVR_SYSHEAD:
            //获取播放库未使用的通道号
            if (!PlayM4_GetPort(&nPort)) {
                break;
            }

            if (dwBufSize > 0) {
                thread->port = nPort;
                if (!PlayM4_OpenStream(nPort, pBuffer, dwBufSize, 1024 * 1024)) {
                    dRet = PlayM4_GetLastError(nPort);
                    break;
                }

                //设置解码回调函数 只解码不显示
                if (!PlayM4_SetDecCallBackMend(nPort, DecCallBack, (quser)dwUser)) {
                    dRet = PlayM4_GetLastError(nPort);
                    break;
                }

                //打开视频解码
                if (!PlayM4_Play(nPort, NULL)) {
                    dRet = PlayM4_GetLastError(nPort);
                    break;
                }

                //打开音频解码, 需要码流是复合流
                if (!PlayM4_PlaySound(nPort)) {
                    dRet = PlayM4_GetLastError(nPort);
                    break;
                }
            }
            break;

        case NET_DVR_STREAMDATA:
            //解码数据
            if (dwBufSize > 0 && nPort != -1) {
                BOOL inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);
                while (!inData) {
                    sleep(10);
                    inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);
                }
            }
            break;
    }
}

Supongo que te gusta

Origin blog.csdn.net/feiyangqingyun/article/details/108232723
Recomendado
Clasificación