• 使用javacv,解码socket接收的H264码流(byte[]),转为yuv处理,最后再合成转为H264


    其实是一个用java实现录像的功能,还没有实现,但解码和转码已经可以。

    1.maven环境,pom.xml配置

     1 <properties>
     2         <javacpp.version>1.4.1</javacpp.version>
     3         <!-- ffmpeg版本 -->
     4         <ffmpeg.version>3.4.2</ffmpeg.version>
     5         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     6         <servlet.version>3.1.0</servlet.version>
     7     </properties>
     8 <dependency>
     9 <groupId>org.bytedeco</groupId>
    10 <artifactId>javacv-platform</artifactId>
    11 <version>${javacpp.version}</version>
    12 </dependency>
    13 <dependency>
    14 <groupId>org.bytedeco</groupId>
    15 <artifactId>javacpp</artifactId>
    16 <version>${javacpp.version}</version>
    17 </dependency>
    18 <dependency>
    19 <groupId>org.bytedeco.javacpp-presets</groupId>
    20 <artifactId>ffmpeg-platform</artifactId>
    21 <version>${ffmpeg.version}-${javacpp.version}</version>
    22 </dependency>
    View Code

    2.代码

      1 package com.br.test;
      2 
      3 import java.io.ByteArrayOutputStream;
      4 import java.io.File;
      5 import java.io.FileOutputStream;
      6 import java.io.IOException;
      7 import java.nio.ByteBuffer;
      8 import org.bytedeco.javacpp.*;
      9 import static org.bytedeco.javacpp.avcodec.*;
     10 import static org.bytedeco.javacpp.avformat.*;
     11 import static org.bytedeco.javacpp.avutil.*;
     12 import static org.bytedeco.javacpp.swscale.*;
     13 
     14 public class NewTest {
     15     // Load only once formats and codecs
     16     static {
     17         av_register_all();
     18 //        avformat_network_init();
     19         avcodec_register_all();
     20     }
     21     public int codec_id;
     22     public AVCodecContext m_pCodecCtx = null; // URL中视频解码部分内容
     23     public AVFrame m_pFrame = null; // 全局使用帧对象
     24     public AVFrame m_pFrameRGB = null;
     25     public AVCodec m_pCodec = null;
     26     public AVCodecParserContext pCodecParserCtx = null;
     27     public AVPacket packet = null;
     28     public SwsContext m_pImageConvertCtx = null; // 构造全局对象,供sws_scale切割图片使用
     29     public SwsContext img_convert_ctx = null;
     30     public Integer count = 0;
     31     public int count_size;
     32     public BytePointer cur_ptr;
     33     public FileOutputStream os;
     34     private ByteArrayOutputStream myByteArrayOutputStream = new ByteArrayOutputStream();
     35 
     36     public NewTest() {
     37         System.out.println("init begin");
     38 
     39         m_pFrame = av_frame_alloc();
     40         codec_id = AV_CODEC_ID_H264;
     41         m_pFrameRGB = av_frame_alloc();
     42         m_pCodec = avcodec_find_decoder(codec_id);
     43 
     44         if (m_pCodec == null) {
     45             System.out.println("Codec not found
    ");
     46         }
     47         m_pCodecCtx = avcodec_alloc_context3(m_pCodec);
     48         if (m_pCodecCtx == null) {
     49             System.out.println("Could not allocate video codec context
    ");
     50         }
     51 
     52         pCodecParserCtx = av_parser_init(codec_id);
     53         if (pCodecParserCtx == null) {
     54             System.out.println("Could not allocate video parser context
    ");
     55         }
     56 
     57         if (avcodec_open2(m_pCodecCtx, m_pCodec, (PointerPointer<Pointer>) null) < 0) {
     58             System.out.println("Could not open codec
    ");
     59         }
     60         img_convert_ctx = sws_getContext(1920, 1088, AV_PIX_FMT_YUV420P, 1920, 1088, AV_PIX_FMT_BGRA, SWS_FAST_BILINEAR,
     61                 null, null, (DoublePointer) null);
     62 
     63         packet = new AVPacket();
     64 
     65         packet = av_packet_alloc();
     66 
     67         av_new_packet(packet, 30000);
     68 
     69         int numBytes = av_image_get_buffer_size(AV_PIX_FMT_BGRA, 1920, 1088, 1);
     70 
     71         BytePointer rgbData = new BytePointer(av_malloc(numBytes));
     72 
     73         av_image_fill_arrays(m_pFrameRGB.data(), m_pFrameRGB.linesize(), rgbData, AV_PIX_FMT_BGRA, 1920, 1088, 1);
     74 
     75         System.out.println("init end");
     76     }
     77 
     78     public void dec_loop(byte[] H264) {
     79 
     80         ByteBuffer data = ByteBuffer.allocate(H264.length);
     81         data.put(H264);
     82         int cur_size = H264.length;
     83         IntPointer pktSize = new IntPointer(packet.size());
     84         BytePointer temp_bp = new BytePointer();
     85         while (cur_size > 0) {
     86 
     87             data.flip();
     88             int slen = av_parser_parse2(pCodecParserCtx, m_pCodecCtx, temp_bp, pktSize, new BytePointer(data), cur_size,
     89                     AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
     90             packet = packet.size(pktSize.get());
     91 
     92             data.position(slen);
     93             data = data.compact();
     94             cur_size -= slen;
     95 
     96             if (pktSize.get() == 0) {
     97                 continue;
     98             }
     99             packet = packet.data(temp_bp);
    100             // for(int i = 0;i <5;i++){
    101             // byte b = packet.data().get(i);
    102             // System.out.print(byteToHex(b)+" ");
    103             // }
    104             // System.out.println("------------------------------!!!!------------------"+packet.size());
    105             // packet.data().asBuffer();
    106 
    107             int asp = avcodec_send_packet(m_pCodecCtx, packet);
    108 
    109             if (avcodec_receive_frame(m_pCodecCtx, m_pFrame) == 0) {
    110                 // m_pFrame.data(0);
    111                 // y = m_pFrame->data[0];1920*1088
    112                 // u = m_pFrame->data[1];1920*1088/4
    113                 // v = m_pFrame->data[2];1920*1088/4
    114 
    115                 System.err.println(
    116                         "->>> decode success   " + "width :" + m_pFrame.width() + " " + "height :" + m_pFrame.height());
    117 
    118                 sws_scale(img_convert_ctx, m_pFrame.data(), m_pFrame.linesize(), 0, m_pCodecCtx.height(),
    119                         m_pFrameRGB.data(), m_pFrameRGB.linesize());
    120                 BytePointer by_bgra_data = m_pFrameRGB.data(0);
    121                 try {
    122 //                    String imgName = "C:/Users/user/Desktop/test/test" + count + ".h264";
    123 //                    saveImg(m_pFrame, imgName);
    124 //                    count++;
    125                     // for (int i = 0; i < 1920 * 1088 * 4; i++) {
    126                     // myByteArrayOutputStream.write(by_bgra_data.get(i));
    127                     // }
    128                     // if (myByteArrayOutputStream.size() == 1920 * 1088 * 4) {
    129                     // File file = new
    130                     // File("C://Users//user//Desktop//test//success.yuv");
    131                     // if (!file.exists()) {
    132                     // file.createNewFile();
    133                     // }
    134                     // FileOutputStream fe = new FileOutputStream(file, true);
    135                     // fe.write(myByteArrayOutputStream.toByteArray());
    136                     // fe.flush();
    137                     // fe.close();
    138                     // myByteArrayOutputStream.reset();
    139                     // }
    140                 } catch (Exception e) {
    141                     e.printStackTrace();
    142                 }
    143             }
    144             // av_packet_unref(packet);
    145         }
    146         // av_packet_free(packet);
    147     }
    148 
    149     public int saveImg(AVFrame pFrame, String out_file) throws IOException {
    150         AVCodec codec = null;
    151         AVPacket pkt = null;
    152         AVStream pAVStream = null;
    153         int ret = -1;
    154         AVDictionary avd = new AVDictionary(null);
    155         int width = pFrame.width(), height = pFrame.height();
    156         // 分配AVFormatContext对象
    157         AVFormatContext pFormatCtx = avformat_alloc_context();
    158         // 设置输出文件格式
    159         pFormatCtx.oformat(av_guess_format("h264", null, null));
    160         if (pFormatCtx.oformat() == null) {
    161             return -1;
    162         }
    163         try {
    164             // 创建并初始化一个和该url相关的AVIOContext
    165             AVIOContext pb = new AVIOContext();
    166             if (avio_open(pb, out_file, AVIO_FLAG_READ_WRITE) < 0) {// dont open
    167                                                                     // file
    168                 return -1;
    169             }
    170             pFormatCtx.pb(pb);
    171             // 构建一个新stream
    172             pAVStream = avformat_new_stream(pFormatCtx, codec);
    173             if (pAVStream == null) {
    174                 return -1;
    175             }
    176             int codec_id = pFormatCtx.oformat().video_codec();
    177             // 设置该stream的信息
    178             AVCodecContext pCodecCtx = pAVStream.codec();
    179             pCodecCtx.codec_id(codec_id);
    180             pCodecCtx.codec_type(AVMEDIA_TYPE_VIDEO);
    181             pCodecCtx.pix_fmt(AV_PIX_FMT_YUV420P);
    182             pCodecCtx.width(width);
    183             pCodecCtx.height(height);
    184             pCodecCtx.time_base().num(1);
    185             pCodecCtx.time_base().den(25);
    186             pCodecCtx.qmin(10);
    187             pCodecCtx.qmax(51);
    188             pCodecCtx.bit_rate(400000);
    189             pCodecCtx.gop_size(12);
    190             pCodecCtx.qcompress(0.6f);
    191 
    192             if (pCodecCtx.codec_id() == AV_CODEC_ID_H264) {
    193                 av_dict_set(avd, "preset", "slow", 0);
    194                 av_dict_set(avd, "tune", "zerolatency", 0);
    195             }
    196 
    197             // Begin Output some information
    198             av_dump_format(pFormatCtx, 0, out_file, 1);
    199             // End Output some information
    200 
    201             // 查找编码器
    202             AVCodec pCodec = avcodec_find_encoder(pCodecCtx.codec_id());
    203             if (pCodec == null) {// codec not found
    204                 return -1;
    205             }
    206             // 设置pCodecCtx的解码器为pCodec
    207             if (avcodec_open2(pCodecCtx, pCodec, avd) < 0) {
    208                 System.err.println("Could not open codec.");
    209                 av_dict_free(avd);
    210                 return -1;
    211             }
    212 
    213             // Write Header
    214             avformat_write_header(pFormatCtx, (PointerPointer<Pointer>) null);
    215 
    216             // 给AVPacket分配足够大的空间
    217             pkt = new AVPacket();
    218             int yuvSize = ((width * height) / 2) * 3;
    219             if (av_new_packet(pkt, yuvSize) < 0) {
    220                 return -1;
    221             }
    222 
    223             int[] got_picture = { 0 };
    224             // encode
    225 
    226             if (avcodec_encode_video2(pCodecCtx, pkt, pFrame, got_picture) >= 0) {
    227                 System.out.println("got_picture[0]:" + got_picture[0]);
    228                 if (got_picture[0] == 1) {
    229                     // flush
    230                     BytePointer pkt_data = pkt.data();
    231                     // 输出pkt数据到文件
    232                     for (int i = 0; i < pkt.size(); i++) {
    233                         myByteArrayOutputStream.write(pkt_data.get(i));
    234                     }
    235                     if (myByteArrayOutputStream.size() == pkt.size()) {
    236                         File file = new File("C://Users//user//Desktop//test//success.h264");
    237                         if (!file.exists()) {
    238                             file.createNewFile();
    239                         }
    240                         FileOutputStream fe = new FileOutputStream(file, true);
    241                         fe.write(myByteArrayOutputStream.toByteArray());
    242                         fe.flush();
    243                         fe.close();
    244                         myByteArrayOutputStream.reset();
    245                     }
    246 
    247                     if ((ret = av_write_frame(pFormatCtx, pkt)) >= 0) {
    248                         // Write Trailer
    249                         if (av_write_trailer(pFormatCtx) >= 0) {
    250                             System.err.println("->>> Encode Successful.   pkt.size():" + pkt.size());
    251                         } else {
    252                             System.err.println("Encode failed.");
    253                         }
    254                     }
    255                 }
    256             }
    257             return ret;
    258             // 结束时销毁
    259         } finally {
    260             if (pkt != null) {
    261                 av_free_packet(pkt);
    262             }
    263             if (pAVStream != null) {
    264                 avcodec_close(pAVStream.codec());
    265             }
    266             if (pFormatCtx != null) {
    267                 avio_close(pFormatCtx.pb());
    268                 avformat_free_context(pFormatCtx);
    269             }
    270         }
    271     }
    272 
    273     public static byte[] conver(ByteBuffer byteBuffer) {
    274         int len = byteBuffer.limit() - byteBuffer.position();
    275         byte[] bytes = new byte[len];
    276 
    277         if (byteBuffer.isReadOnly()) {
    278             return null;
    279         } else {
    280             byteBuffer.get(bytes);
    281         }
    282         return bytes;
    283     }
    284 
    285     public static String byteToHex(byte b) {
    286         String hex = Integer.toHexString(b & 0xFF);
    287         if (hex.length() < 2) {
    288             hex = "0" + hex;
    289         }
    290         return hex;
    291     }
    292 
    293     public static void main(String[] args) {
    294         NewTest test = new NewTest();
    295     }
    296 
    297 }
    View Code

    因为在网上很少有用javacv来解码的例子,只能自己踩坑前行,一点点的测试,所以可能有很多错误或可以优化的地方。

    自己项目中用到,以此来记录,便于以后再遇到相同的问题。

  • 相关阅读:
    『轉』windows文件的占用空间与文件大小
    『轉』asterisk入门连载二
    vm系統出現This Virtual Machine Appears To Be In Use的問題
    linux 7788
    鸿蒙开发板外设控制 之 实现按键“按下事件”和“释放事件”的通用框架(V0.0.1)
    【开发板试用报告】学习GPIO编程
    前言「HarmonyOS应用开发基础篇」
    【开发板试用报告】鸿蒙OS环境搭建及代码烧录
    动态设置和访问cxgrid列的Properties
    cxgrid导出excel
  • 原文地址:https://www.cnblogs.com/zh-peng/p/10076590.html
Copyright © 2020-2023  润新知