Cómo decodificar la secuencia h264

Busqué mucho pero no encuentro una biblioteca decente para resolver mi problema. Recibo un flujo h264 de la red, y quiero decodificarlo de memoria y mostrarlo en tiempo real. Algo como este pseudocódigo abajo:

cv::Mat frame;
while (true)
{
    if (newDataArrived)
    {
        void* h264Buffer; // address with current h264 stream
        size_t h264BufferSize; // size of the stream
        LibraryINeed::UpdateFrame(frame, h264Buffer, h264BufferSize); // !?
    }
    ...
    imshow("display", frame); // show most recent frame
}

¿Hay alguna biblioteca que proporcione esta funcionalidad?

Pregunta hecha hace 3 años, 5 meses, 0 días - Por csscraftsman


2 Respuestas:

  • Parece que estás buscando una biblioteca que te permita decodificar secuencias H.264 en tiempo real y mostrar el video resultante en una ventana. Una opción popular para lograr esto es utilizar la biblioteca FFmpeg, que es ampliamente utilizada para la decodificación y codificación de varios formatos de video, incluido H.264.

    Te proporcionaré un ejemplo de cómo podrías ajustar tu código utilizando la biblioteca FFmpeg. Por favor ten en cuenta que este ejemplo es simplificado y podrías necesitar ajustarlo según tus necesidades específicas:

    cpp
    include include extern "C"
    {
    include include include }
    
    cv::Mat frame;
    
    int main()
    {
        av_register_all();
        AVFormatContext formatContext = avformat_alloc_context();
    
        if (avformat_open_input(&formatContext, "tu_archivo_h264", NULL, NULL) != 0)
        {
            std::cerr << "Error al abrir el archivo de video" << std::endl;
            return -1;
        }
    
        if (avformat_find_stream_info(formatContext, NULL) < 0)
        {
            std::cerr << "Error al obtener la información del stream" << std::endl;
            return -1;
        }
    
        AVCodec codec = avcodec_find_decoder(AV_CODEC_ID_H264);
        AVCodecContext codecContext = avcodec_alloc_context3(codec);
        avcodec_open2(codecContext, codec, NULL);
    
        AVFrame avFrame = av_frame_alloc();
        AVPacket packet;
    
        while (true)
        {
            int ret = av_read_frame(formatContext, &packet);
            if (ret < 0)
            {
                break;
            }
    
            if (packet.stream_index == 0) // Assuming video stream is at index 0
            {
                ret = avcodec_send_packet(codecContext, &packet);
                if (ret < 0)
                {
                    std::cerr << "Error en avcodec_send_packet()" << std::endl;
                    break;
                }
    
                ret = avcodec_receive_frame(codecContext, avFrame);
                if (ret == 0)
                {
                    cv::Mat decodedFrame(codecContext->height, codecContext->width, CV_8UC3, avFrame->data[0]);
                    cv::cvtColor(decodedFrame, frame, cv::COLOR_YUV2BGR);
    
                    imshow("display", frame); // show most recent frame
                    cv::waitKey(1);
    
                    av_frame_unref(avFrame);
                }
            }
    
            av_packet_unref(&packet);
        }
    
        avformat_close_input(&formatContext);
        avformat_free_context(formatContext);
    
        return 0;
    }
    

    Recuerda que este código es solo un ejemplo básico y deberás ajustarlo según tus necesidades específicas. Además, asegúrate de tener instalada la biblioteca FFmpeg en tu sistema y de vincularla correctamente al compilar tu código. Espero que esta información te sea útil para empezar a decodificar secuencias H.264 en tiempo real.

    Respondida el Dec 18, 2020 a las 15:29 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Sí, hay bibliotecas disponibles que pueden ayudarte a decodificar secuencias h264 de memoria y mostrar los fotogramas resultantes en tiempo real. Aquí hay algunas opciones:

    1. OpenCV:

    OpenCV Contrib incluye un decodificador h264 que se puede usar para decodificar secuencias h264 desde la memoria. Ejemplo de código:

    cpp
    cv::Mat frame;
    while (true) {
        if (newDataArrived) {
            void h264Buffer; // address with current h264 stream
            size_t h264BufferSize; // size of the stream
            cv::Mat h264Mat(1, h264BufferSize, CV_8UC1, h264Buffer);
            cv::VideoCapture cap;
            cap.open(h264Mat, cv::CAP_FFMPEG);
            cap >> frame;
        }
        ...
        imshow("display", frame); // show most recent frame
    }
    

    2. FFmpeg:

    FFmpeg es una potente biblioteca multimedia que también proporciona capacidades de decodificación h264. Ejemplo de código (usando la API de C):

    c
    AVFrame frame = av_frame_alloc();
    AVCodecContext codec_ctx = avcodec_alloc_context3(codec);
    avcodec_open2(codec_ctx, codec, NULL);
    while (true) {
        if (newDataArrived) {
            void h264Buffer; // address with current h264 stream
            size_t h264BufferSize; // size of the stream
            av_new_packet(pkt, h264BufferSize);
            memcpy(pkt->data, h264Buffer, h264BufferSize);
            avcodec_send_packet(codec_ctx, pkt);
            avcodec_receive_frame(codec_ctx, frame);
            // Convertir el fotograma AVFrame a OpenCV Mat
            cv::Mat opencv_frame(frame->height, frame->width, CV_8UC3, frame->data[0]);
        }
        ...
        imshow("display", opencv_frame); // show most recent frame
    }
    

    3. GStreamer:

    GStreamer es un marco multimedia que proporciona un pipeline para procesar secuencias multimedia, incluida la decodificación h264. Ejemplo de código (usando la API de C):

    c
    GstElement pipeline = gst_pipeline_new("h264-decoder");
    GstElement h264parser = gst_element_factory_make("h264parse", "h264parser");
    GstElement h264decoder = gst_element_factory_make("avdec_h264", "h264decoder");
    GstElement videosink = gst_element_factory_make("autovideosink", "videosink");
    gst_bin_add_many(GST_BIN(pipeline), h264parser, h264decoder, videosink, NULL);
    gst_element_link_many(h264parser, h264decoder, videosink, NULL);
    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    while (true) {
        if (newDataArrived) {
            void h264Buffer; // address with current h264 stream
            size_t h264BufferSize; // size of the stream
            GstBuffer buffer = gst_buffer_new_wrapped(h264Buffer, h264BufferSize);
            GstSample sample = gst_sample_new(buffer, NULL, NULL, NULL);
            gst_element_push_sample(h264parser, sample);
        }
        ...
        // Recupera el último fotograma del pipeline
        GstSample sample = gst_sample_new(buffer, NULL, NULL, NULL);
        GstMapInfo info;
        gst_sample_map(sample, &info, GST_MAP_READ);
        cv::Mat opencv_frame(info.height, info.width, CV_8UC3, info.data);
        gst_sample_unmap(sample, &info);
        imshow("display", opencv_frame); // show most recent frame
    }
    

    Todas estas bibliotecas son capaces de decodificar secuencias h264 de memoria y proporcionar fotogramas decodificados en un formato compatible con OpenCV. La elección de la biblioteca específica dependerá de tus requisitos específicos, como el rendimiento, la compatibilidad entre plataformas y las características adicionales que necesites.

    Respondida el Dec 18, 2020 a las 15:39 - por Gemini

    Votos positivos: 0 | Votos negativos: 0