I am trying to read an audio RTP stream in my application, but I am getting this error:
[pcm_mulaw # 03390580] PCM channels out of bounds
I can read the RTP stream fine with ffplay:
ffplay -i test.sdp -protocol_whitelist file,udp,rtp
I generate the RTP stream using this command:
ffmpeg -re -f lavfi -i aevalsrc="sin(400*2*PI*t)" -ar 8000 -f mulaw -f rtp rtp://127.0.0.1:8554
// SDP
v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat 57.25.101
m=audio 8554 RTP/AVP 0
b=AS:64
And here is my source code:
#include "stdafx.h"
#include <math.h>
extern "C"
{
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#include <libavformat/avformat.h>
}
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
#define ERRBUFFLEN 200
char errbuf[ERRBUFFLEN];
#define av_err2str(ret) av_strerror(ret, errbuf, ERRBUFFLEN)
/*
* Audio decoding.
*/
static void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *inCodec;
AVCodecContext *inCodecCtx = NULL;
int len;
FILE *f, *outfile;
uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
AVFrame *decoded_frame = NULL;
AVFormatContext *inFormatCtx = NULL;
AVFrame *inFrame = NULL;
AVFrame *outFrame = NULL;
int ret;
av_init_packet(&avpkt);
AVDictionary *d = NULL; // "create" an empty dictionary
int listen = false;
listen = true;
if (listen)
{
av_dict_set(&d, "protocol_whitelist", "file,udp,rtp", 0); // add an entry
printf("Listening mode.\n");
}
else {
printf("Connecting mode.\n");
}
// Open video file
ret = avformat_open_input(&inFormatCtx, filename, NULL, &d);
if (ret <0)
{
printf_s("Failed: cannot open input.\n");
av_strerror(ret, errbuf, ERRBUFFLEN);
fprintf(stderr, "avformat_open_input() fail: %s\n", errbuf);
exit(1);
}
printf_s("Retrieve stream information.\n");
ret = avformat_find_stream_info(inFormatCtx, NULL);
if (ret <0)
{
printf_s("Failed: cannot find stream.\n");
av_strerror(ret, errbuf, ERRBUFFLEN);
fprintf(stderr, "avformat_find_stream_info() fail: %s\n", errbuf);
exit(1);
}
av_dump_format(inFormatCtx, 0, filename, 0);
int stream_idx = -1;
for (int i = 0; i < inFormatCtx->nb_streams; i++)
if (inFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_idx = i;
break;
}
if (stream_idx == -1)
{
fprintf(stderr, "Video stream not found\n");
exit(1);
}
inCodec = avcodec_find_decoder(inFormatCtx->streams[stream_idx]->codec->codec_id);
if (!inCodec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
inCodecCtx = avcodec_alloc_context3(inCodec);
if (!inCodecCtx) {
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
/* Error here */
ret = avcodec_open2(inCodecCtx, inCodec, NULL);
if (ret < 0) {
fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
exit(1);
}
(...more code)
I know something is wrong, but what is it? Suggestions and tips are much appreciated.
I found out that the stream attributes were not set automatically, so I had to manually set them before calling avcodec_open2():
inCodecCtx->sample_rate = 8000;
inCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
inCodecCtx->channels = 1;
inCodecCtx->channel_layout = AV_CH_LAYOUT_MONO;
Hope this helps someone who encountered the same issue as I do.
There's also a dedicated function in avcodec.h :
int error = avcodec_parameters_to_context(inCodecCtx, inFormatCtx->streams[stream_idx]->codecpar);
if (error < 0) {
// something went wrong
}
(See https://www.ffmpeg.org/doxygen/3.2/demuxing__decoding_8c_source.html, line 182).
Thanks, you helped me :-D
Just wanted to add, if you don't know them, you can get these parameters from the file.
Here is my code searching for an audio stream, getting a decoder for it, and setting up the parameters from the formatContext.
Note that my code is Scala calling the Java-CPP wrapper around FFMEG
val formatContext = chkNull(avformat.avformat_alloc_context())
val inputFormat = avformat.av_find_input_format(format)
if (inputFormat == null) throw new Error(s"Format '${format}' is not supported")
formatContext.iformat(inputFormat)
chk(avformat.avformat_open_input(formatContext, "<path to audio file goes here>", null, null))
val audioStreams = (0 until formatContext.nb_streams) filter { i: Int =>
formatContext.streams(i).codecpar().codec_type() == avutil.AVMEDIA_TYPE_AUDIO
}
val audioStream = audioStreams.size match {
case 0 => throw new Error("No Audio Stream found")
case 1 => audioStreams.head
case _ => throw new Error("More than one Audio Streams found")
}
val codecParameters = formatContext.streams(audioStream).codecpar()
val decoder = chkNull(avcodec.avcodec_find_decoder(codecParameters.codec_id()))
val codecContext = chkNull(avcodec.avcodec_alloc_context3(decoder))
codecContext.sample_rate(codecParameters.sample_rate())
codecContext.sample_fmt(codecParameters.format())
codecContext.channels(codecParameters.channels())
codecContext.channel_layout(codecParameters.channel_layout())
chk(avcodec.avcodec_open2(codecContext, null, null.asInstanceOf[AVDictionary]))
Related
I am using libav to parsing a MJPEG Stream to get the packet data for resending it over an websocket, now I am facing the issue that ffmpeg use only 25 FPS. I know the Stream has 60FPS for 100%
These are the values after open and read the stream Informations:
avg_frame_rate = 0, r_frame_rate = 25/1, time_base = 1/25
I tried to set all of them to a setting for 60FPS, but this looks has no effect.
I have set time_base to 1/60 and also frame rates to 60 but none of them are making any difference.
Because its an MJPEG Stream libav needs to guess the framerate, but I don't know why setting time_base or framerate does not have any effect.
Maybe someone could help me how I could force 60 FPS for parsing an MJEPG Stream, this would be great.
Thank u
This is just an Illustration of my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
int main(int argc, char *argv[]) {
AVFormatContext *fmt_ctx = NULL;
AVCodecContext *codec_ctx = NULL;
AVCodec *codec = NULL;
AVPacket pkt;
if (argc < 2) {
fprintf(stderr, "Usage: %s <mjpeg-stream-url>\n", argv[0]);
exit(1);
}
av_register_all();
if (avformat_open_input(&fmt_ctx, argv[1], NULL, NULL) < 0) {
fprintf(stderr, "Could not open stream '%s'\n", argv[1]);
exit(1);
}
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not find stream information\n");
exit(1);
}
int video_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
if (video_stream_index < 0) {
fprintf(stderr, "Could not find video stream\n");
exit(1);
}
AVStream *video_stream = fmt_ctx->streams[video_stream_index];
stream->time_base = (AVRational) { 1, 60};
stream->avg_frame_rate = (AVRational) { 60, 1 };
stream->r_frame_rate = (AVRational) { 60, 1 };
av_init_packet(&pkt);
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
if (pkt.stream_index == video_stream_index) {
// Sending it to an websocket ....
}
av_packet_unref(&pkt);
}
avformat_close_input(&fmt_ctx);
avformat_free_context(fmt_ctx);
return 0;
}
The AVDictionary sets additional/specific parameters to endpoints and if you call it while opening the endpoint, it uses these specific parameters to open the endpoint.
It could take multiple key - value pairs and applies all of them to the endpoint.
I suppose creating an AVDictionay and passing a "framerate", "60" or may be "framerate" "60000/1000" parameter could solve your problem. Or if your source supports format_code then you could also use the format code something like "format_code", "Hp60" in the AVDictionary.
AVDictionary *options{nullptr};
// You should find the right parameter name
// like "frame_rate", "format_code", "sample_rate" etc.
// You can also set multiple options there!
// you may put all the possibilities once!
if(av_dict_set(&options, "framerate", "60", 0) < 0) {
fprintf(stderr, "Could not set the option!\n");
exit(1);
}
if (avformat_open_input(&fmt_ctx, argv[1], NULL, &options) < 0) {
fprintf(stderr, "Could not open stream '%s'\n", argv[1]);
exit(1);
}
I got the latest version binaries of ffmpeg from here. When I examine CPU and GPU usages when I play a video by its ffplay, I see that GPU is used during play. Not much using of CPU also indicates it. But when I get the latest version sources from the original site, I can't use GPU. To clarify, I include a player test program I wrote until now. When I uncomment the line which includes avcodec_find_decoder_by_name("h264_cuvid"), I get error -1. The error happens in avcodec_open2 with the description of Operation not permitted.
CString format(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
char buf[512];
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return buf;
}
int CplayerDlg::play()
{
FILE *fp = fopen("video_files/1010.brf", "rb");
if (!fp)
{
AfxMessageBox("can't open video file");
return -1;
}
RecordFrame frame;
RecordHeader hdr;
fread(&frame, sizeof(frame), 1, fp);
if (frame.frameType != FRAME_TYPE_HEADER)
{
AfxMessageBox("record file doesn't begin with header");
return -1;
}
fread(&hdr, sizeof(hdr), 1, fp);
GetDlgItem(IDC_DIM)->SetWindowText(format("%dx%d", hdr.width, hdr.height));
GetDlgItem(IDC_CODEC_ID)->SetWindowText(format("%d", hdr.codecId));
GetDlgItem(IDC_PIXEL_FORMAT)->SetWindowText(format("%d", hdr.pixelFormat));
GetDlgItem(IDC_TIMEBASE)->SetWindowText(format("%d/%d", hdr.timebaseNum, hdr.timebaseDen));
AVCodec *pCodec;
#if 0
#define CHECK(decoder)\
pCodec = avcodec_find_decoder_by_name(#decoder);\
AfxMessageBox(pCodec ? #decoder " found" : "can't find " #decoder);
CHECK(h264_cuvid);
#undef CHECK
#endif
pCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
//pCodec = avcodec_find_decoder_by_name("h264_cuvid");
if (!pCodec)
{
AfxMessageBox("can't find h264 decoder");
return -1;
}
AVCodecContext *pCodecContext = avcodec_alloc_context3(pCodec);
if (!pCodecContext)
{
AfxMessageBox("can't allocate codec context");
return -1;
}
#if 0
// enumerating available codecs
//av_register_all();
avcodec_register_all();
AVCodec *current_codec = av_codec_next(NULL);
while (current_codec != NULL)
{
TRACE("%s\n", current_codec->name);
current_codec = av_codec_next(current_codec);
}
#endif
int err = avcodec_open2(pCodecContext, pCodec, NULL);
if (err != 0)
{
char buf[AV_ERROR_MAX_STRING_SIZE];
av_make_error_string(buf, AV_ERROR_MAX_STRING_SIZE, err);
char buf2[AV_ERROR_MAX_STRING_SIZE];
sprintf(buf2, "%d (%x): %s\n", err, err, buf);
AfxMessageBox(buf2);
return -1;
}
AfxMessageBox("operation completed successfully");
fclose(fp);
return 0;
}
I have a problem with decoding of gray images encoded with FFV1 codec.
I successfully encode 16 bit gray image (with avcodec_receive_packet(...) function) and save AvPacket data to file. Then I read this data from file and try to decode (with avcodec_decode_video2 or avcodec_send_packet/avcodec_receive_frame) with no success:
when I try to decode packet with avcodec_decode_video2 function I get an error "Access violation occurred, unable to write location 0x0000000000000000".
when I try to decode packet with avcodec_send_packet/avcodec_receive_frame functions I get an error "chroma shift parameters 7 0 are invalid".
I compared packets after encoding and before decoding and all fields and values seems to be the same. I even try to decode packet just after avcodec_receive_packet (encoding function), however with the same error.
I use the 4.0 version of ffmpeg and the program is based on decode_video.c and encode_video.c examples.
When I use containers (eg. avi) to support read/write encoded images from file (based on demuxing_decoding.c and muxing.c examples) I successfully encode and decode frames with FFV1. However I cannot use containers, because I want to encode frames with different resolutions and mix few video sources together. Additionally the compression level is significantly lower (falls from 2.9 to 2.2) for few hundred of images, what is also very surprising.
So my question is how to correctly save/read (from binary file not container) and prepare AVPacker for decoding with FFV1.
Any help is greatly appreciated.
The decoding code:
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
}
#pragma warning(disable: 4996)
#define INBUF_SIZE 4096
#define FF_INPUT_BUFFER_PADDING_SIZE 64
uint8_t endcode[4];
AVCodecContext *c, c2;
AVCodec *codec;
int i, ret, x, y;
AVFrame *frame;
AVPacket *pkt, *pkt_temp;
FILE *encodedVideoFile;
AVDictionary *opts = NULL;
uint8_t *video_dst_data[4] = { NULL };
int video_dst_linesize[4];
int imageSize;
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
/* flush the encoder */
frame = NULL;
encode();
/* add sequence end code to have a real MPEG file */
//fwrite(endcode, 1, sizeof(endcode), encodedVideoFile);
fclose(encodedVideoFile);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
}
void initDecoding(const char *filename)
{
/* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
/* find the MPEG-1 video decoder */
codec = avcodec_find_decoder(AV_CODEC_ID_FFV1);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
/* resolution must be a multiple of two */
c->width = 1280;
c->height = 484;
/* frames per second */
c->time_base.den = 1;
c->time_base.num = 10;
c->bits_per_raw_sample = 16;
c->framerate.den = 10;
c->framerate.num = 1;
c->pix_fmt = AV_PIX_FMT_GRAY16;
//Version of FFV1 codec
c->level = 3;
/* Init the decoders, with or without reference counting */
av_dict_set(&opts, "refcounted_frames", 0 ? "1" : "0", 0);
if ((ret = avcodec_open2(c, codec, &opts)) < 0) {
return;
}
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
ret = av_image_alloc(video_dst_data, video_dst_linesize,
c->width, c->height, c->pix_fmt, 4);
if (ret < 0) {
fprintf(stderr, "Could not allocate raw video buffer\n");
}
encodedVideoFile = fopen(filename, "rb");
if (!encodedVideoFile) {
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
ret = av_frame_get_buffer(frame, 32);
if (ret < 0) {
fprintf(stderr, "Could not allocate the video frame data\n");
exit(1);
}
/* make sure the frame data is writable */
ret = av_frame_make_writable(frame);
if (ret < 0)
exit(1);
}
void closeDecoding()
{
fclose(encodedVideoFile);
av_parser_close(parser);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
}
void decodePacket()
{
size_t data_size;
int *got_frame = 0;
read_packt_from_file(pkt, encodedVideoFile);
ret = av_frame_is_writable(frame);
//First decoding function
/*ret = avcodec_decode_video2(c, frame, got_frame, pkt);
if (ret < 0) {
fprintf(stderr, "Error decoding video frame (%s)\n");
}*/
ret = avcodec_send_packet(c, pkt);
if (ret < 0) {
fprintf(stderr, "Error sending a packet for decoding\n");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_frame(c, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error during decoding\n");
exit(1);
}
printf("saving frame %3d\n", c->frame_number);
fflush(stdout);
}
}
size_t read_packt_from_file(AVPacket *packet, FILE *file)
{
size_t ret = 0;
int size;
uint8_t * data;
//av_packet_from_data
ret = fread(packet, sizeof(AVPacket), 1, file);
size = packet->size;
data = new uint8_t[size];
ret = fread(data, size, 1, file);
av_new_packet(packet, size);
av_packet_from_data(packet, data, size);
return ret;
}
//To write encoded AVPacket
size_t write_packt_to_file(AVPacket *packet, FILE *file)
{
size_t ret = 0;
ret = fwrite(packet, sizeof(AVPacket), 1, file);
ret = fwrite(packet->data, packet->size, 1, file);
if (packet->buf) {
fwrite(packet->buf->data, packet->buf->size, 1, file);
}
fflush(file);
return ret;
}
I have RTP packets with VP8 encoded data. I want to write it to a mkv file or webm file. I tried a bit, but I have not been successful yet. My code is as below
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <libavutil/avassert.h>
#include <libavutil/channel_layout.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
bool mfmedia_init_ffmpeg();
void mfmedia_ffprint(void *handle, int cnt, const char *format, va_list valist);
int main()
{
mfmedia_init_ffmpeg();
return 0;
}
bool mfmedia_init_ffmpeg()
{
bool ret = false;
AVCodecContext* context;
AVCodec* codec;
AVFormatContext* format;
AVStream* stream;
unsigned fps = 24;
unsigned width = 768;
unsigned height = 608;
av_register_all();
int err = 0;
char errorLog[128] = { 0 };
av_log_set_level(AV_LOG_TRACE);
av_log_set_callback(mfmedia_ffprint);
err = avformat_alloc_output_context2(&format, NULL, NULL, "o.webm");
if (err < 0)
{
printf("Cannot allocate output context: %s\n", av_make_error_string(errorLog, 128, err));
goto last;
}
codec = avcodec_find_encoder(AV_CODEC_ID_VP8);
if (!codec)
{
printf("Cannot find an encoder\n");
goto last;
}
context = avcodec_alloc_context3(codec);
if (!context)
{
printf("Cannot allocate a codec context\n");
goto last;
}
context->pix_fmt = AV_PIX_FMT_YUV420P;
context->width = width;
context->height = height;
context->time_base = (AVRational){1, fps};
err = avcodec_open2(context, codec, NULL);
if(err < 0)
{
printf("Cannot open codec: %s\n", av_make_error_string(errorLog, 128, err));
goto last;
}
stream = avformat_new_stream(format, codec);
if (!stream)
{
printf("Cannot create a new stream\n");
goto last;
}
//av_dump_format(format, 0, "o.webm", 1);
err = avio_open(&format->pb, "o.webm", AVIO_FLAG_WRITE);
if(err < 0)
{
printf("Cannot open output: %s\n", av_make_error_string(errorLog, 128, err));
goto last;
}
err = avformat_write_header(format, NULL);
if(err < 0)
{
printf("Cannot write header to stream: %s\n", av_make_error_string(errorLog, 128, err));
goto last;
}
ret = true;
last:
return ret;
}
void mfmedia_ffprint(void *handle, int cnt, const char *format, va_list valist)
{
char *log_buf = (char *)malloc(38192);
int length;
if(log_buf)
{
time_t rawtime;
time ( &rawtime );
length = vsprintf(log_buf ,format, valist);
length += sprintf((log_buf + length), " : %s ", ctime (&rawtime));
*(log_buf + length) = 0x0;
printf("%s", log_buf);
fflush(stdout);
free(log_buf);
}
}
It is failing when I call avformat_write_header.
From trace log (towards end) I see
Setting default whitelist 'file,crypto'
: Fri Jan 19 16:58:57 2018
Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
: Fri Jan 19 16:58:57 2018
dimensions not set
: Fri Jan 19 16:58:57 2018
Cannot write header to stream: Invalid argument
Please let me know why avformat_write_header is failing.
This should work, enter this code snipped right above of: //av_dump_format(format, 0, "o.webm", 1);
/* copy the stream parameters to the muxer */
err = avcodec_parameters_from_context(stream->codecpar, context);
if (err < 0) {
fprintf(stderr, "Could not copy the stream parameters\n");
exit(1);
}
env: ubuntu 16.04 64 bit; ffmpeg 3.3.2 build whih cuda cuvid libnpp...
use ffmpeg cmd: ffmpeg -vsync 0 -c:v h264_cuvid -i test.264 -f rawvideo test.yuv works fine, the generated yuv file is ok.
BUT When I decode this 264 file by my code use 'h264_cuvid' decoder, something problem happens, this is my code:
#include <stdio.h>
#define __STDC_CONSTANT_MACROS
#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#ifdef __cplusplus
};
#endif
#endif
//test different codec
#define TEST_H264 1
#define TEST_HEVC 0
int main(int argc, char* argv[])
{
AVCodec *pCodec;
AVCodecContext *pCodecCtx= NULL;
AVCodecParserContext *pCodecParserCtx=NULL;
FILE *fp_in;
FILE *fp_out;
AVFrame *pFrame;
const int in_buffer_size=4096;
unsigned char in_buffer[in_buffer_size + FF_INPUT_BUFFER_PADDING_SIZE]= {0};
unsigned char *cur_ptr;
int cur_size;
AVPacket packet;
int ret, got_picture;
#if TEST_HEVC
enum AVCodecID codec_id=AV_CODEC_ID_HEVC;
char filepath_in[]="bigbuckbunny_480x272.hevc";
#elif TEST_H264
AVCodecID codec_id=AV_CODEC_ID_H264;
char filepath_in[]="2_60_265to264.264";
#else
AVCodecID codec_id=AV_CODEC_ID_MPEG2VIDEO;
char filepath_in[]="bigbuckbunny_480x272.m2v";
#endif
char filepath_out[]="mainSend.yuv";
int first_time=1;
//av_log_set_level(AV_LOG_DEBUG);
avcodec_register_all();
// pCodec = avcodec_find_decoder(codec_id);
pCodec = avcodec_find_decoder_by_name("h264_cuvid");
if (!pCodec)
{
printf("Codec not found\n");
return -1;
}
pCodecCtx = avcodec_alloc_context3(pCodec);
if (!pCodecCtx)
{
printf("Could not allocate video codec context\n");
return -1;
}
pCodecParserCtx=av_parser_init(pCodec->id);
if (!pCodecParserCtx)
{
printf("Could not allocate video parser context\n");
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
{
printf("Could not open codec\n");
return -1;
}
//Input File
fp_in = fopen(filepath_in, "rb");
if (!fp_in)
{
printf("Could not open input stream\n");
return -1;
}
//Output File
fp_out = fopen(filepath_out, "wb");
if (!fp_out)
{
printf("Could not open output YUV file\n");
return -1;
}
pFrame = av_frame_alloc();
av_init_packet(&packet);
while (1)
{
cur_size = fread(in_buffer, 1, in_buffer_size, fp_in);
if (cur_size == 0)
break;
cur_ptr=in_buffer;
while (cur_size>0)
{
int len = av_parser_parse2(
pCodecParserCtx, pCodecCtx,
&packet.data, &packet.size,
cur_ptr, cur_size,
AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
cur_ptr += len;
cur_size -= len;
if(packet.size==0)
continue;
//Some Info from AVCodecParserContext
printf("[Packet]Size:%6d\t",packet.size);
switch(pCodecParserCtx->pict_type)
{
case AV_PICTURE_TYPE_I:
printf("Type:I\tNumber:%4d\n",pCodecParserCtx->output_picture_number);
break;
case AV_PICTURE_TYPE_P:
printf("Type:P\t");
break;
case AV_PICTURE_TYPE_B:
printf("Type:B\t");
break;
default:
printf("Type:Other\t");
break;
}
printf("Number:%4d\n",pCodecParserCtx->output_picture_number);
AVFrame* myFrame = av_frame_alloc();
ret = avcodec_decode_video2(pCodecCtx, myFrame, &got_picture, &packet);
if (ret < 0)
{
printf("Decode Error.\n");
return ret;
}
if (got_picture)
{
if(first_time)
{
printf("\nCodec Full Name:%s\n",pCodecCtx->codec->long_name);
printf("width:%d\nheight:%d\n\n",pCodecCtx->width,pCodecCtx->height);
first_time=0;
}
//Y, U, V
for(int i=0; i<myFrame->height; i++)
{
fwrite(myFrame->data[0]+myFrame->linesize[0]*i,1,myFrame->width,fp_out);
}
for(int i=0; i<myFrame->height/2; i++)
{
fwrite(myFrame->data[1]+myFrame->linesize[1]*i,1,myFrame->width/2,fp_out);
}
for(int i=0; i<myFrame->height/2; i++)
{
fwrite(myFrame->data[2]+myFrame->linesize[2]*i,1,myFrame->width/2,fp_out);
}
// printf("pframe's width height %d %d\t key frame %d\n",myFrame->width,myFrame->height,myFrame->key_frame);
printf("Succeed to decode 1 frame!\n");
av_frame_free(&myFrame);
}
}
}
fclose(fp_in);
fclose(fp_out);
av_parser_close(pCodecParserCtx);
av_frame_free(&pFrame);
avcodec_close(pCodecCtx);
av_free(pCodecCtx);
return 0;
}
In this demo code, I call h264_cuvid by vcodec_find_decoder_by_name("h264_cuvid");
BUT the code crash at fwrite(myFrame->data[2]+myFrame->linesize[2]*i,1,myFrame->width/2,fp_out);
So after debug with codeblocks, I found that there is no data in myFrame->data[2] codeblocks watching window
Any suggestion? thanks!
"h264" decoder's frame pix format is AV_PIX_FMT_YUV420P
BUT "h264_cuvid" decoder's frame pix format is AV_PIX_FMT_NV12
so, edit code to
for(int i=0; i<myFrame->height; i++)
{
fwrite(myFrame->data[0]+myFrame->linesize[0]*i,1,myFrame->width,fp_out);
}
for(int i=0; i<myFrame->height/2; i++)
{
fwrite(myFrame->data[1]+myFrame->linesize[1]*i,1,myFrame->width,fp_out);
}
Works fine