Hi, i have a h264 file, i need to decode the video and save the frames to jpg.
I simply modified samples/02_video_dec_cuda/videodec_main.cpp, add some code below dec->capture_plane.dqBuffer, like this:
/* Dequeue a valid capture_plane buffer that contains YUV BL data */
if (dec->capture_plane.dqBuffer(v4l2_buf, &dec_buffer, NULL, 0))
{...
}
// encode jpg
NvJPEGEncoder* jpegenc = NvJPEGEncoder::createJPEGEncoder("jpenenc");
unsigned long out_buf_size = 1920 * 1080 * 3 / 2;
unsigned char *out_buf = new unsigned char[out_buf_size];
int ret = jpegenc->encodeFromFd(dec_buffer->planes[0].fd, JCS_YCbCr, &out_buf, out_buf_size);
if (ret < 0) cerr << "Error: jpeg encode fail" << endl;
static int ii = 0;
std::ostringstream oss;
oss << "frame" << ii++ << ".jpg";
std::ofstream ofs(oss.str());
ofs.write((char *)out_buf, out_buf_size);
ofs.close();
delete[] out_buf;
delete jpegenc;
/* If converter is created, send the decoded data to converter,
otherwise, just return the buffer to converter capture plane */
if (ctx->conv)
....
It works well for the sample video /usr/src/jetson_multimedia_api/data/Video/sample_outdoor_car_1080p_10fps.h264, but generates pure green pictures for my test video.
I checked decoder output, no problem.
test video:
test.h264 (3.9 MB)
Hi,
The decoded buffer is in YUV420 blocklinear format. You should put the code in conv0_capture_dqbuf_thread_callback() to encode buffers in YUV420 pitchlinear.
I thought jpeg encoder only works on blocklinear format (not the other way around)? because i checked jpeg_encode_main.cpp, it converts from pitchlinear to blocklinear before encoding to jpg.
Anyway, i tried move the code to conv0_capture_dqbuf_thread_callback(), it crashed as expected. (yeah, crash on pitchlinear buffer, which i came across multiple times.)
(gdb) bt
#0 0x0000007fb23d8f18 in () at /usr/lib/aarch64-linux-gnu/tegra/libnvtvmr.so
#1 0x0000007fb23d9df8 in () at /usr/lib/aarch64-linux-gnu/tegra/libnvtvmr.so
#2 0x0000007fb7cb6208 in jpegTegraEncoderCompress () at /usr/lib/aarch64-linux-gnu/tegra/libnvjpeg.so
#3 0x0000007fb7c80354 in jpeg_write_raw_data () at /usr/lib/aarch64-linux-gnu/tegra/libnvjpeg.so
#4 0x000000555556ce1c in NvJPEGEncoder::encodeFromFd(int, J_COLOR_SPACE, unsigned char**, unsigned long&, int) ()
#5 0x000000555555dde8 in conv0_capture_dqbuf_thread_callback(v4l2_buffer*, NvBuffer*, NvBuffer*, void*) ()
#6 0x0000005555599574 in NvV4l2ElementPlane::dqThread(void*) ()
#7 0x0000007fb7f89088 in start_thread (arg=0x7faa33de1f) at pthread_create.c:463
#8 0x0000007fb6a374ec in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78
Besides, when i add the code after dec->capture_plane.dqBuffer, it works fine for sample_outdoor_car_1080p_10fps.h264, but not my test video. I think it’s video pixel format relative, but i can’t find any difference between the two samples. (both nv12, 1920x1080).
i think i made a mistake. i checked the video pixel format with ffmpeg, it’s not the same. my video is yuvj420p, sample_outdoor_car_1080p_10fps.h264 is yuv420p.
Input #0, h264, from '.\sample_outdoor_car_1080p_10fps.h264':=0/0
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (High), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 10 fps, 10 tbr, 1200k tbn, 20 tbc
Input #0, h264, from 'test.h264': 0KB vq= 0KB sq= 0B f=0/0
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (Main), yuvj420p(pc, progressive), 1920x1080, 25 fps, 25 tbr, 1200k tbn, 50 tbc
however, dec->capture_plane.getFormat() gives V4L2_PIX_FMT_NV12M for both videos.
Hi,
Please modify the capture plant format:
ret = ctx->conv->setCapturePlaneFormat((ctx->out_pixfmt == 1 ?
V4L2_PIX_FMT_NV12M :
V4L2_PIX_FMT_YUV420M),
crop.c.width,
crop.c.height,
V4L2_NV_BUFFER_LAYOUT_PITCH);
to V4L2_NV_BUFFER_LAYOUT_BLOCKLINEAR. And apply jpeg encoding in conv0_capture_dqbuf_thread_callback(). See if this works.
i did what you say, now it throws error somewhere else.
root@inspur-desktop:/usr/src/jetson_multimedia_api/samples/02_video_dec_cuda# ./video_dec_cuda /usr/src/jetson_multimedia_api/data/Video/sample_outdoor_car_1080p_10fps.h264 H264 --disable-rendering --input-nalu -o 1
Opening in BLOCKING MODE
NvMMLiteOpen : Block : BlockType = 261
NVMEDIA: Reading vendor.tegra.display-size : status: 6
NvMMLiteBlockCreate : Block : BlockType = 261
Starting decoder capture loop thread
Video Resolution: 1920x1080
pixel format: 842091854, nv12: 842091854, yuv420p: 842091865
libv4l2_nvvidconv (0):(802) (INFO) : Allocating (14) OUTPUT PLANE BUFFERS Layout=1
libv4l2_nvvidconv (0):(818) (INFO) : Allocating (14) CAPTURE PLANE BUFFERS Layout=1
[ERROR] (NvBuffer.cpp:169) <Buffer> Could not map buffer 0, plane 0
[ERROR] (NvV4l2ElementPlane.cpp:720) <conv0> Capture Plane:Error during setup
Error in converter capture plane setup
Error in query_and_set_capture
Exiting decoder capture loop thread
[ERROR] (NvV4l2ElementPlane.cpp:178) <dec0> Output Plane:Error while DQing buffer: Broken pipe
Error DQing buffer at output plane
Decoder is in error
App run failed
it seems ctx->conv->capture_plane.setupPlane() failed
Hi,
The decoded buffer is in NvBufferColorFormat_NV12_ER, which is not supported in NvVideoConverter. Please call NvBufferTransform() to convert to NvBufferColorFormat_NV12 or NvBufferColorFormat_YVU420, and then call encodeFromFd().
It works fine now after transforming to NvBufferColorFormat_NV12.
Thanks.
1 Like