Wei Dongshan Embedded Linux_3 USB Camera Monitoring_Mobile App agrega la función de grabación de video (2)

Conecte un artículo Wei Dongshan incrustado Linux_3 del monitoreo _ teléfono con cámara USB aplicación para aumentar la función (a) la grabación, comenzó a introducir el proceso de modificación para el original Marco de Aplicación

1. División del módulo

   i) (Módulo principal) Captura y reproducción de video

   ii) Cambio de modo de visualización

   iii) Tomar fotografías

   iv) Video

   v) pantalla fps

   vi) Explorar y eliminar video

Segundo, la realización de cada módulo.

2.1 (módulo principal) captura y reproducción de video

2.1.1 Materiales de referencia:

1) El marco principal (decodificación, marco de lectura) se refiere a Lei Xiaohua : 100 líneas de código para implementar el reproductor de video más simple basado en FFMPEG + SDL (SDL1.x)

      Para el proceso del marco principal, consulte la publicación de blog anterior de Lei Xiaohua, que no se repetirá aquí.

2) Pantalla de marco, referencia: Android usa FFmpeg (2) - realización simple de transmisión de video

     El flujo de visualización de cuadros es aproximadamente el siguiente:

     imagen

2.2 Cambio de modo de visualización

Idea de implementación: utilice las funciones de escala y relleno de av_filter para escalar y obtener el relleno de cuatro lados necesario para cada marco original obtenido.

El código del cuerpo del cuadro principal se refiere al ejemplo de uso del filtro FFMPEG (implementación de escalado de video, recorte, marca de agua, etc.) , que no se repetirá aquí.

En cuanto a cómo cambiar el parámetro de escala (y el parámetro de pad) en los dos modos de visualización, no se ha encontrado el mejor método (después de la prueba, av_opt_set () solo es válido para draw_text (ver abajo: pantalla de 2.5 fps ), pero para scale y pad Inválido),

En la actualidad, el método tonto se adopta temporalmente:

1) Defina dos plantillas filter_descr y sus correspondientes AVFilterGraph, AVFilterContext

/ * Se utiliza para mantener el modo de visualización de la relación de aspecto * / 
const  char * m_filter_descr_template = " scale =% d:% d, pad =% d:% d:% d:% d: blue, drawtext = fontfile = / sdcard / data /FreeSerif.ttf:fontsize=20:text=fps:x=(w-tw-%d):y=%d ";
 char   m_filter_descr [200];
/ * Para el modo de visualización en pantalla completa * / 
const  char * m_filter_descr2_template = " scale =% d:% d, pad =% d:% d:% d:% d: blue, drawtext = fontfile = / sdcard / data / FreeSerif. ttf: tamaño de fuente = 20: texto = fps: x = (w-tw-5): y = 5 ";
 char   m_filter_descr2 [200];

/ * Se utiliza para mantener el modo de visualización de la relación de aspecto * /
AVFilterContext * m_buffersink_ctx1;
AVFilterContext * m_buffersrc_ctx1;
AVFilterGraph * m_filter_graph1;

/ * Para el modo de visualización en pantalla completa * /
AVFilterContext * m_buffersink_ctx2;
AVFilterContext * m_buffersrc_ctx2;
AVFilterGraph * m_filter_graph2;

2) Durante la inicialización, primero llame a keep_img_AR () para calcular previamente el valor de filter_descr correspondiente a los dos modos de visualización

int keep_img_AR ( int nSrcW, int nSrcH, int nDstW, int nDstH) 
{ / * Calcule la relación ancho-alto con bordes negros en la parte superior e inferior, o izquierda y derecha con bordes negros, cuántos bordes negros * / int imgW = 0, imgH = 0;
     int padW = 0, padH = 0; // Debe redondearse
     a un múltiplo de 2; de lo contrario, ffmpeg informará un error al calcular el pad: Área de entrada que no está dentro del área acolchada o 
    nDstW = nDstW / 2 * 2; 
    nDstH = nDstH / 2 * 2; 
    imgW = nSrcW * nDstH / nSrcH / 2 * 2; 
    imgH = nSrcH * nDstW / nSrcW / 2 * 2; if (imgW <nDstW) { 
        padW = (nDstW-imgW) / 2; 
        imgH = nDstH / 2 * 2 ; // imgW = -1; 
    } más if (imgH <nDstH) {
    
    

    
        
     
        padH = (nDstH-imgH) / 2; 
        imgW = nDstW / 2 * 2; // imgH = -1; 
    } 
    sprintf (m_filter_descr, m_filter_descr_template, imgW, imgH, nDstW, nDstH, padW, padH, padW + 5, padH + 5); 
    sprintf (m_filter_descr2, m_filter_descr2_template, nDstW, nDstH, nDstW, nDstH, 0, 0); retorno 1; 
}
        

    

3) Luego llame a init_filters () para inicializar m_filter_graph1, m_buffersink_ctx1, m_buffersrc_ctx1 y m_filter_graph2, m_buffersink_ctx2, m_buffersrc_ctx2

     El código de init_filters () se refiere al ejemplo de uso del filtro FFMPEG (implementación de escalado de video, recorte, marca de agua, etc.) , que no se repetirá aquí.

4) Y cambiar el modo de reproducción en realidad es cambiar (m_filter_graph1, m_buffersink_ctx1, m_buffersrc_ctx1) y (m_filter_graph2, m_buffersink_ctx2, m_buffersrc_ctx2) triplete

/ ** 
 * Cuando el jugador que tenga la relación de aspecto de vídeo 
 * / 
void playVideoKeepAspectRatio () 
{ 
    m_play_video_mode = PLAY_VIDEO_KEEP_ASPECT_RATIO; 
    m_filter_graph = m_filter_graph1; 
    m_buffersrc_ctx = m_buffersrc_ctx1; 
    m_buffersink_ctx = m_buffersink_ctx1; 
} / ** 
 * relleno de reproducción área de visualización de vídeo 
 * / void playVideoFullScreen () 
{ 
    m_play_video_mode = PLAY_VIDEO_FULL_SCREEN; 
    m_filter_graph = m_filter_graph2; 
    m_buffersrc_ctx = m_buffersrc_ctx2; 
    m_buffersink_ctx = m_buffersink_ctx2; 
}


Nota: Con respecto al cambio del modo de visualización, otra forma de lograr esto es usar sws_scale () y av_picture_pad (), referencia: use la biblioteca lib de ffmpeg para lograr la relación ancho / alto original / estiramiento de la ventana de video

Pero la cantidad de código es grande, y después de las pruebas, encontré algunos problemas, como:

-Después de agregar el draw_text de av_filter, la pantalla fps saltará un poco hacia arriba y hacia abajo, el motivo debe ser investigado

-fps posicionamiento es más difícil de lograr (debido al ancho de la almohadilla)

Entonces, al final, este método no se adoptó (pero el algoritmo para calcular la escala y el pad en keep_img_AR () se refiere a este artículo).

2.3 Tomar fotos

Ideas de implementación:

1) Defina m_pFrameCur para representar el marco adquirido actualmente

2) En el bucle while de la función de reproducción de video videoStreamStartPlay (), use av_frame_ref (m_pFrameCur, pFrame) para hacer que m_pFrameCur apunte al cuadro adquirido actualmente

3) __save_frame_2_jpeg (file_path, m_pFrameCur, m_input_codec_ctx-> pix_fmt) para guardar el marco actual en el archivo especificado

     Código de referencia: ffmpeg realiza la colección-vista previa-fotografía de la cámara mjpeg , no hay más detalles aquí

2.4 Video

Referencia: Cómo usar la API de FFmpeg para recopilar video de cámara y audio de micrófono, y realizar la función de grabar archivos

En la demostración de este artículo, la función de grabación está bien encapsulada en una clase CAVOutputStream, básicamente la uso intacta para la implementación subyacente de la función de grabación.

El trabajo que agregué es llamar a la máquina de estado video_capture_state_machine () en el bucle while de la función de reproducción de video videoStreamStartPlay (). El código es aproximadamente el siguiente:

vacío video_capture_state_machine (AVFrame * pFrame) 
{ interruptor (m_video_capture_state) 
    { caso VIDEO_CAPTURE_START: 
            LOGD ( " VIDEO_CAPTURE_START "); 
            m_start_time = av_gettime (); 
            m_OutputStream.SetVideoCodec (AV_CODEC_ID_H264); // 设置 视频 编码 器 属性if (true == m_OutputStream.OpenOutputStream (m_save_video_path.c_str ())) 
                m_video_capture_state = VIDEO_CAPTURE_IN_PROGRESS; de lo contrario 
                m_video_capture_state = VIDEO_CAPTURE_IDLE; romper ;
        caso VIDEO_CAPTURE_IN_PROGRESS: 
            LOGD ("
    
        
            
            
            VIDEO_CAPTURE_IN_PROGRESS "); 
            m_OutputStream.write_video_frame (m_input_format_ctx-> Streams [m_video_stream_index], m_input_format_ctx-> corrientes [m_video_stream_index] -> codec-> pix_fmt, pFrame, av_gettime () - m_start_time); descanso ;
         caso VIDEO_CAPTURE_STOP: 
            LOGD (" VIDEO_CAPTURE_STOP ") ; 
            m_OutputStream.CloseOutput (); 
            m_video_capture_state = VIDEO_CAPTURE_IDLE; break ;
         default :
             if (m_video_capture_state == VIDEO_CAPTURE_IDLE) { 
                LOGD (" VIDEO_CAPTURE_IDLE "); 
            } else
            
            
            { 
                LOGD (" m_video_capture_state :% d ", m_video_capture_state); 
            } Romper ; 
    } // conmutador eo (m_video_capture_state) 
}
            

Las interfaces de la capa nativa y la capa JAVA son las siguientes:

/ * 开始 录像 * / 
void videoStreamStartCapture ( const  char * file_path) 
{ 
    m_save_video_path = file_path; 
    m_video_capture_state = VIDEO_CAPTURE_START; 
} / * 停止 录像 * / void videoStreamStopCapture () 
{ 
    m_video_capture_state = VIDEO_CAPTURE_STOP; 
}


Pantalla de 2.5 fps

La idea de realización es la misma: 2.2 Cambio de modo de visualización .

La visualización dinámica del valor fps se realiza mediante av_opt_set (filter_ctx_draw_text-> priv, "text", str_fps, 0).

2.6 Explorar y eliminar video

Ideas de implementación: utilice básicamente el marco original de la aplicación, con solo unos pocos cambios. Principalmente de la siguiente manera:

1) MainActivity.java

      Cuando el usuario hace clic en el botón "Foto", aparece un cuadro de diálogo de alerta que le solicita que seleccione el tipo de navegación y, de acuerdo con la elección del usuario, llame antes de iniciar la actividad (intención)

      intent.putExtra ("picturePath", picturePath);

      intent.putExtra ("scan_type", ScanPicActivity.SCAN_TYPE_VIDEO);

      O

      intent.putExtra ("picturePath", videoRecordPath);

      intent.putExtra ("scan_type", ScanPicActivity.SCAN_TYPE_PIC);

2) ScanPicActivity.java

      -En la función init (), scan_type = getIntent (). GetIntExtra ("scan_type", SCAN_TYPE_PIC); guarde el tipo de exploración actual

      -Scan_type se agrega a cada lugar donde está involucrada la cadena de caracteres "jpeg". Se omite el código; consulte el código fuente del proyecto para obtener más información.

3) Generic.java

      Imite getShrinkedPic (), agregue la función getShrinkedPicFromVideo (), el núcleo es ThumbnailUtils.createVideoThumbnail (). Se omite el código; consulte el código fuente del proyecto para obtener más información.

Materiales de referencia:

1) Wei Dongshan Embedded Linux Training Phase 3 project monitoreo de cámara usb real, código fuente de la aplicación de teléfono móvil

2) Tutorial oficial de Android: https://developer.android.google.cn/guide/

3) AndroidStudio3.x desarrolla y depura el código C ++ de Android-NDK

4) Notas de desarrollo de NDK-CMake build JNI

5) Serie de artículos del blog de Lei Xiaohua: [Resumen] FFMPEG códec de audio y video método de aprendizaje basado en cero

6) Android usa FFmpeg (2): realización simple de transmisión de video

7) Cómo usar la API de FFmpeg para recopilar video de cámara y audio de micrófono, y realizar la función de grabar archivos

8) ffmpeg realiza la colección, previsualiza y toma fotos de la cámara mjpeg

9) Use ejemplos de filtro FFMPEG (para lograr escalado de video, recorte, marca de agua, etc.)

10) Use la biblioteca lib de ffmpeg para lograr la relación ancho / alto original / extensión de la ventana de video

11) ffmpeg logra un ajuste dinámico del contenido de subtítulos

12) Resumen de uso de Ffmpeg (a continuación)

13) Imprimir información de depuración de FFmpeg en Android logcat

Supongo que te gusta

Origin www.cnblogs.com/normalmanzhao2003/p/12695432.html
Recomendado
Clasificación