Tegra_Multimedia API 例程学习之6--06_jpeg_decode

概述

使用硬件解码一张jpeg的图片,这里也使用了两个方法实现,一种效率高一些,另一种效率低一些。

编译运行

编译就不说了,进入源码直接make
运行

 $ ./jpeg_decode num_files <number of files to decode> \
     <in-file1> <out-file1> ...<in-filen> <out-filen> [OPTIONS]
      $ ./jpeg_decode num_files 1 ../../data/Picture/nvidia-logo.jpg ../../data/Picture/nvidia-logo.yuv

流程图

在这里插入图片描述
output plane用于接收输入,capture plane用于产生输出,这个和我们平常的理解似乎有些唱反调,但是就是这样规定的。可以通过两个api 函数进行解码:

  • decodeToFd ,数据格式和Tegra的硬件格式相匹配,后面需要一个converter进行转换。
  • decodeToBuffer,它包含了转化buffer到software format,所以可以直接把后面的数据写入文件。但是这个效率要低一些,因为软件进行转化。

这个例子相对好看一些,比如前面的decode那一个程序,里面太长,不容易理清程序。这个程序就简单一些了

先看decodeToBuffer

首先看一下JpegDeocder的操作,创建一个实例,然后直接decodeToBuffer就可以了,最后写入文件

ctx.jpegdec = NvJPEGDecoder::createJPEGDecoder("jpegdec");

 NvBuffer *buffer;
 ret = ctx.jpegdec->decodeToBuffer(&buffer, ctx.in_buffer,
            ctx.in_file_size, &pixfmt, &width, &height);
            
write_video_frame(ctx.out_file[i], *buffer);

再看DecodeToFd

 ctx.jpegdec = NvJPEGDecoder::createJPEGDecoder("jpegdec");
 ctx.conv = NvVideoConverter::createVideoConverter("conv");
  ret = ctx.jpegdec->decodeToFd(fd, ctx.in_buffer, ctx.in_file_size, pixfmt,
          width, height);
          
ret = ctx.conv->setCropRect(0, 0, width, height);
 // Set conv output plane format
      ret =
        ctx.conv->setOutputPlaneFormat(pixfmt, width,
            height, V4L2_NV_BUFFER_LAYOUT_PITCH);
            
// Set conv capture plane format
      ret =
        ctx.conv->setCapturePlaneFormat(pixfmt, width,
            height,
            V4L2_NV_BUFFER_LAYOUT_PITCH);
  //转换器的输入output plane为DMABUF,这是从解码器输出的
 // REQBUF, EXPORT and MAP conv output plane buffers
      ret = ctx.conv->output_plane.setupPlane(V4L2_MEMORY_DMABUF, 1, false, false);
      
// REQBUF and EXPORT conv capture plane buffers
      // No need to MAP since buffer will be shared to next component
      // and not read in application
      ret =
        ctx.conv->capture_plane.setupPlane(V4L2_MEMORY_MMAP, 1,
            true, false);
 // conv output plane STREAMON
      ret = ctx.conv->output_plane.setStreamStatus(true);
      TEST_ERROR(ret < 0, "Error in output plane streamon for conv", cleanup);

      // conv capture plane STREAMON
      ret = ctx.conv->capture_plane.setStreamStatus(true);
      TEST_ERROR(ret < 0, "Error in capture plane streamon for conv", cleanup);
      //转换器的输出capture plane需要使用内存映射。
      ctx.conv->
        capture_plane.setDQThreadCallback(conv_capture_dqbuf_thread_callback);

      // Start threads to dequeue buffers on conv capture plane
      ctx.conv->capture_plane.startDQThread(&ctx);

整个代码

/*
 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of NVIDIA CORPORATION nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "NvUtils.h"
#include <errno.h>
#include <fstream>
#include <iostream>
#include <malloc.h>
#include <string.h>
#include <unistd.h>

#include "jpeg_decode.h"

#define TEST_ERROR(cond, str, label) if(cond) { \
                                        cerr << str << endl; \
                                        error = 1; \
                                        goto label; }

using namespace std;

static void
abort(context_t * ctx)
{
    ctx->got_error = true;
    ctx->conv->abort();
}

static bool
conv_capture_dqbuf_thread_callback(struct v4l2_buffer *v4l2_buf,
                                   NvBuffer * buffer, NvBuffer * shared_buffer,
                                   void *arg)
{
    context_t *ctx = (context_t *) arg;

    if (!v4l2_buf)
    {
        cerr << "Failed to dequeue buffer from conv capture plane" << endl;
        abort(ctx);
        return false;
    }

    write_video_frame(ctx->out_file[ctx->current_file++], *buffer);
    return false;
}

static uint64_t
get_file_size(ifstream * stream)
{
    uint64_t size = 0;
    streampos current_pos = stream->tellg();
    stream->seekg(0, stream->end);
    size = stream->tellg();
    stream->seekg(current_pos, stream->beg);
    return size;
}

static void
set_defaults(context_t * ctx)
{
    memset(ctx, 0, sizeof(context_t));
    ctx->use_fd = true;
    ctx->stress_test = 1;
    ctx->current_file = 0;
}

static int
jpeg_decode_proc(context_t& ctx, int argc, char *argv[])
{
    int ret = 0;
    int error = 0;
    int fd = 0;
    uint32_t width, height, pixfmt;
    int i = 0;

    set_defaults(&ctx);

    ret = parse_csv_args(&ctx, argc, argv);
    TEST_ERROR(ret < 0, "Error parsing commandline arguments", cleanup);

    for(i = 0; i < ctx.num_files; i++)
    {
      ctx.in_file[i] = new ifstream(ctx.in_file_path[i]);
      TEST_ERROR(!ctx.in_file[i]->is_open(), "Could not open input file", cleanup);

      ctx.out_file[i] = new ofstream(ctx.out_file_path[i]);
      TEST_ERROR(!ctx.out_file[i]->is_open(), "Could not open output file", cleanup);
    }

    ctx.jpegdec = NvJPEGDecoder::createJPEGDecoder("jpegdec");
    TEST_ERROR(!ctx.jpegdec, "Could not create Jpeg Decoder", cleanup);

    for(i = 0; i < ctx.num_files; i++)
    {
      ctx.in_file_size = get_file_size(ctx.in_file[i]);
      ctx.in_buffer = new unsigned char[ctx.in_file_size];
      ctx.in_file[i]->read((char *) ctx.in_buffer, ctx.in_file_size);

      if (!ctx.use_fd)
      {
        NvBuffer *buffer;
        ret = ctx.jpegdec->decodeToBuffer(&buffer, ctx.in_buffer,
            ctx.in_file_size, &pixfmt, &width, &height);
        TEST_ERROR(ret < 0, "Could not decode image", cleanup);
        cout << "Image Resolution - " << width << " x " << height << endl;
        write_video_frame(ctx.out_file[i], *buffer);
        delete buffer;
        goto cleanup;
      }

      ctx.conv = NvVideoConverter::createVideoConverter("conv");
      TEST_ERROR(!ctx.conv, "Could not create Video Converter", cleanup);

      ret = ctx.jpegdec->decodeToFd(fd, ctx.in_buffer, ctx.in_file_size, pixfmt,
          width, height);
      TEST_ERROR(ret < 0, "Could not decode image", cleanup);
      cout << "Image Resolution - " << width << " x " << height << endl;

      ret = ctx.conv->setCropRect(0, 0, width, height);
      TEST_ERROR(ret < 0, "Could not set crop rect for conv0", cleanup);

      // Set conv output plane format
      ret =
        ctx.conv->setOutputPlaneFormat(pixfmt, width,
            height, V4L2_NV_BUFFER_LAYOUT_PITCH);
      TEST_ERROR(ret < 0, "Could not set output plane format for conv", cleanup);

      // Set conv capture plane format
      ret =
        ctx.conv->setCapturePlaneFormat(pixfmt, width,
            height,
            V4L2_NV_BUFFER_LAYOUT_PITCH);
      TEST_ERROR(ret < 0, "Could not set capture plane format for conv", cleanup);

      // REQBUF, EXPORT and MAP conv output plane buffers
      ret = ctx.conv->output_plane.setupPlane(V4L2_MEMORY_DMABUF, 1, false, false);
      TEST_ERROR(ret < 0, "Error while setting up output plane for conv",
          cleanup);

      // REQBUF and EXPORT conv capture plane buffers
      // No need to MAP since buffer will be shared to next component
      // and not read in application
      ret =
        ctx.conv->capture_plane.setupPlane(V4L2_MEMORY_MMAP, 1,
            true, false);
      TEST_ERROR(ret < 0, "Error while setting up capture plane for conv",
          cleanup);

      // conv output plane STREAMON
      ret = ctx.conv->output_plane.setStreamStatus(true);
      TEST_ERROR(ret < 0, "Error in output plane streamon for conv", cleanup);

      // conv capture plane STREAMON
      ret = ctx.conv->capture_plane.setStreamStatus(true);
      TEST_ERROR(ret < 0, "Error in capture plane streamon for conv", cleanup);

      ctx.conv->
        capture_plane.setDQThreadCallback(conv_capture_dqbuf_thread_callback);

      // Start threads to dequeue buffers on conv capture plane
      ctx.conv->capture_plane.startDQThread(&ctx);

      // Enqueue all empty conv capture plane buffers
      for (uint32_t i = 0; i < ctx.conv->capture_plane.getNumBuffers(); i++)
      {
        struct v4l2_buffer v4l2_buf;
        struct v4l2_plane planes[MAX_PLANES];

        memset(&v4l2_buf, 0, sizeof(v4l2_buf));
        memset(planes, 0, MAX_PLANES * sizeof(struct v4l2_plane));

        v4l2_buf.index = i;
        v4l2_buf.m.planes = planes;

        ret = ctx.conv->capture_plane.qBuffer(v4l2_buf, NULL);
        if (ret < 0)
        {
          cerr << "Error while queueing buffer at conv capture plane" << endl;
          abort(&ctx);
          goto cleanup;
        }
      }
      //因为只是一张图片,所以这里没有循环
      {
        struct v4l2_buffer v4l2_buf;
        struct v4l2_plane planes[MAX_PLANES];

        memset(&v4l2_buf, 0, sizeof(v4l2_buf));
        memset(planes, 0, MAX_PLANES * sizeof(struct v4l2_plane));

        v4l2_buf.index = 0;
        v4l2_buf.m.planes = planes;
        planes[0].m.fd = fd;//这是连接 decoder和converter的地方
        planes[0].bytesused = 1234;

        ret = ctx.conv->output_plane.qBuffer(v4l2_buf, NULL);
        if (ret < 0)
        {
          cerr << "Error while queueing buffer at conv output plane" << endl;
          abort(&ctx);
          goto cleanup;
        }
      }

      // Wait till all capture plane buffers on conv are dequeued
      ctx.conv->capture_plane.waitForDQThread(2000);

cleanup:
      if (ctx.conv && ctx.conv->isInError())
      {
        cerr << "VideoConverter is in error" << endl;
        error = 1;
      }

      if (ctx.got_error)
      {
        error = 1;
      }
      delete ctx.conv;
      delete[] ctx.in_buffer;
    }

    for(i = 0; i < ctx.num_files; i++)
    {

      delete ctx.in_file[i];
      delete ctx.out_file[i];

      free(ctx.in_file_path[i]);
      free(ctx.out_file_path[i]);
    }
    // Destructors do all the cleanup, unmapping and deallocating buffers
    // and calling v4l2_close on fd
    delete ctx.jpegdec;

    return -error;
}

  int
main(int argc, char *argv[])
{
    context_t ctx;
    int ret = 0;
    int iterator_num = 0; //save iterator number

    do
    {
        ret = jpeg_decode_proc(ctx, argc, argv);
        iterator_num++;
    } while((ctx.stress_test != iterator_num) && ret == 0);

    if (ret)
    {
        cout << "App run failed" << endl;
    }
    else
    {
        cout << "App run was successful" << endl;
    }

    return ret;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值