RBG görüntülerini H264 karelerine kodlamak için x264 C API nasıl kullanılır? Zaten bir dizi RBG görüntüsü oluşturdum, şimdi bu sırayı H264 çerçevelerinin bir dizisine nasıl dönüştürebilirim? Özellikle, bu RGB görüntü dizisini, tek bir başlangıç H264 anahtar karesinden ve ardından H264 çerçevelerinden oluşan bir H264 karesi dizisine nasıl kodlarım?Biri x264 C API kullanarak bir dizi görüntüyü H264'e nasıl kodlar?
cevap
Her şeyden önce: x264.h dosyasını kontrol edin, her işlev ve yapı için daha fazla veya daha az başvuru içerir. İndirmede bulabileceğiniz x264.c dosyası örnek bir uygulama içerir. Çoğu insan bunu kendinizin üzerine koymayı söylüyor, ancak yeni başlayanlar için oldukça karmaşık buluyorum, ancak yine de geriye düşmek için bir örnek.
Önce, x264_param_t türünde, parametreleri tanımlayan iyi bir site olan http://mewiki.project357.com/wiki/X264_Settings türünde bazı parametreler ayarlayabilirsiniz. Ayrıca, bazı (bazen oldukça karmaşık) tüm parametreleri anlamaya gerek kalmadan bazı işlevleri hedeflemenize olanak veren x264_param_default_preset
işlevine de bakın.
x264_t* encoder = x264_encoder_open(¶m);
x264_picture_t pic_in, pic_out;
x264_picture_alloc(&pic_in, X264_CSP_I420, w, h)
şöyle Kodçözücüyü başlatabilir Bundan sonra
x264_param_t param;
x264_param_default_preset(¶m, "veryfast", "zerolatency");
param.i_threads = 1;
param.i_width = width;
param.i_height = height;
param.i_fps_num = fps;
param.i_fps_den = 1;
// Intra refres:
param.i_keyint_max = fps;
param.b_intra_refresh = 1;
//Rate control:
param.rc.i_rc_method = X264_RC_CRF;
param.rc.f_rf_constant = 25;
param.rc.f_rf_constant_max = 35;
//For streaming:
param.b_repeat_headers = 1;
param.b_annexb = 1;
x264_param_apply_profile(¶m, "baseline");
: Ayrıca
Bu benim kodundan bazı örnek kurulduğundan (muhtemelen "taban" profili isteyeceksiniz) sonradan x264_param_apply_profile
kullanmak
X264 YUV420P verilerini bekler (bazılarını da sanırım, ama bu ortak olan). Görüntüleri doğru formata dönüştürmek için libswscale'i (ffmpeg'den) kullanabilirsiniz. Bunun başlatılması şu şekildedir (RGB verisini 24bpp ile kabul ediyorum).
struct SwsContext* convertCtx = sws_getContext(in_w, in_h, PIX_FMT_RGB24, out_w, out_h, PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);
kodlama her kare için yapmak, o zaman bu kadar basittir:
//data is a pointer to you RGB structure
int srcstride = w*3; //RGB stride is just 3*width
sws_scale(convertCtx, &data, &srcstride, 0, h, pic_in.img.plane, pic_in.img.stride);
x264_nal_t* nals;
int i_nals;
int frame_size = x264_encoder_encode(encoder, &nals, &i_nals, &pic_in, &pic_out);
if (frame_size >= 0)
{
// OK
}
Bu olacak almak umut;) kendimi Başlamak için üzerine uzun bir süre geçirdi. X264, delice güçlü ama bazen karmaşık bir yazılım parçasıdır.
düzenleme: Diğer parametreleri kullandığınızda gecikmiş çerçeveler olacak, bu benim parametrelerimde (çoğunlukla nolatency seçeneğinden dolayı) durum böyle değil. Bu durumda, frame_size bazen sıfır olacaktır ve x264_encoder_delayed_frames
işlevi 0 döndürmediği sürece x264_encoder_encode
'u çağırmanız gerekir. Ancak bu işlevsellik için x264.c ve x264.h içine daha derin bir göz atmalısınız.
Ham yuva çerçeveleri oluşturan bir örnek yükledim ve bunları x264 kullanarak kodlarım. Tam kod burada bulunabilir: https://gist.github.com/roxlu/6453908
'da bulunabilir. Çözümünüzün bir özetini buraya ekleyebilirsiniz, böylece bağlantınızın ömrünü tamamlamış olur. – krsteeve
FFmpeg katedilebilen ömeği 2.8.6 bunun için bir üniforma API ortaya çıkarır olarak x264 için bir sarıcı, iyi bir fikir olarak FFpmeg Kullanılması
çoklu kodlayıcılar. Dolayısıyla, biçimleri değiştirmeye ihtiyacınız varsa, yeni bir API öğrenmek yerine yalnızca bir parametreyi değiştirebilirsiniz.
Örnek, generate_rgb
tarafından oluşturulan bazı renkli çerçeveleri sentezler ve kodlar.
Çerçeve türünün (I, P, B) mümkün olduğunca az sayıda anahtar çerçeveye sahip olması (ideal olarak sadece ilk) burada açıklanmıştır: https://stackoverflow.com/a/36412909/895245 Burada belirtildiği gibi, çoğu uygulama için bunu önermiyorum.
burada çerçeve tipi kontrolü yapmak anahtar hatları
şunlardır:/* Minimal distance of I-frames. This is the maximum value allowed,
or else we get a warning at runtime. */
c->keyint_min = 600;
ve:
if (frame->pts == 1) {
frame->key_frame = 1;
frame->pict_type = AV_PICTURE_TYPE_I;
} else {
frame->key_frame = 0;
frame->pict_type = AV_PICTURE_TYPE_P;
}
sonra bir kare tipi ile kontrol edilebilir:
ffprobe -select_streams v \
-show_frames \
-show_entries frame=pict_type \
-of csv \
tmp.h264
belirtildiği gibi at: https://superuser.com/questions/885452/extracting-the-index-of-key-frames-from-a-video-using-ffmpeg
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
static AVCodecContext *c = NULL;
static AVFrame *frame;
static AVPacket pkt;
static FILE *file;
struct SwsContext *sws_context = NULL;
static void ffmpeg_encoder_set_frame_yuv_from_rgb(uint8_t *rgb) {
const int in_linesize[1] = { 3 * c->width };
sws_context = sws_getCachedContext(sws_context,
c->width, c->height, AV_PIX_FMT_RGB24,
c->width, c->height, AV_PIX_FMT_YUV420P,
0, 0, 0, 0);
sws_scale(sws_context, (const uint8_t * const *)&rgb, in_linesize, 0,
c->height, frame->data, frame->linesize);
}
uint8_t* generate_rgb(int width, int height, int pts, uint8_t *rgb) {
int x, y, cur;
rgb = realloc(rgb, 3 * sizeof(uint8_t) * height * width);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
cur = 3 * (y * width + x);
rgb[cur + 0] = 0;
rgb[cur + 1] = 0;
rgb[cur + 2] = 0;
if ((frame->pts/25) % 2 == 0) {
if (y < height/2) {
if (x < width/2) {
/* Black. */
} else {
rgb[cur + 0] = 255;
}
} else {
if (x < width/2) {
rgb[cur + 1] = 255;
} else {
rgb[cur + 2] = 255;
}
}
} else {
if (y < height/2) {
rgb[cur + 0] = 255;
if (x < width/2) {
rgb[cur + 1] = 255;
} else {
rgb[cur + 2] = 255;
}
} else {
if (x < width/2) {
rgb[cur + 1] = 255;
rgb[cur + 2] = 255;
} else {
rgb[cur + 0] = 255;
rgb[cur + 1] = 255;
rgb[cur + 2] = 255;
}
}
}
}
}
return rgb;
}
/* Allocate resources and write header data to the output file. */
void ffmpeg_encoder_start(const char *filename, int codec_id, int fps, int width, int height) {
AVCodec *codec;
int ret;
codec = avcodec_find_encoder(codec_id);
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);
}
c->bit_rate = 400000;
c->width = width;
c->height = height;
c->time_base.num = 1;
c->time_base.den = fps;
c->keyint_min = 600;
c->pix_fmt = AV_PIX_FMT_YUV420P;
if (codec_id == AV_CODEC_ID_H264)
av_opt_set(c->priv_data, "preset", "slow", 0);
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
file = fopen(filename, "wb");
if (!file) {
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_image_alloc(frame->data, frame->linesize, c->width, c->height, c->pix_fmt, 32);
if (ret < 0) {
fprintf(stderr, "Could not allocate raw picture buffer\n");
exit(1);
}
}
/*
Write trailing data to the output file
and free resources allocated by ffmpeg_encoder_start.
*/
void ffmpeg_encoder_finish(void) {
uint8_t endcode[] = { 0, 0, 1, 0xb7 };
int got_output, ret;
do {
fflush(stdout);
ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
if (ret < 0) {
fprintf(stderr, "Error encoding frame\n");
exit(1);
}
if (got_output) {
fwrite(pkt.data, 1, pkt.size, file);
av_packet_unref(&pkt);
}
} while (got_output);
fwrite(endcode, 1, sizeof(endcode), file);
fclose(file);
avcodec_close(c);
av_free(c);
av_freep(&frame->data[0]);
av_frame_free(&frame);
}
/*
Encode one frame from an RGB24 input and save it to the output file.
Must be called after ffmpeg_encoder_start, and ffmpeg_encoder_finish
must be called after the last call to this function.
*/
void ffmpeg_encoder_encode_frame(uint8_t *rgb) {
int ret, got_output;
ffmpeg_encoder_set_frame_yuv_from_rgb(rgb);
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
if (frame->pts == 1) {
frame->key_frame = 1;
frame->pict_type = AV_PICTURE_TYPE_I;
} else {
frame->key_frame = 0;
frame->pict_type = AV_PICTURE_TYPE_P;
}
ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < 0) {
fprintf(stderr, "Error encoding frame\n");
exit(1);
}
if (got_output) {
fwrite(pkt.data, 1, pkt.size, file);
av_packet_unref(&pkt);
}
}
/* Represents the main loop of an application which generates one frame per loop. */
static void encode_example(const char *filename, int codec_id) {
int pts;
int width = 320;
int height = 240;
uint8_t *rgb = NULL;
ffmpeg_encoder_start(filename, codec_id, 25, width, height);
for (pts = 0; pts < 100; pts++) {
frame->pts = pts;
rgb = generate_rgb(width, height, pts, rgb);
ffmpeg_encoder_encode_frame(rgb);
}
ffmpeg_encoder_finish();
}
int main(void) {
avcodec_register_all();
encode_example("tmp.h264", AV_CODEC_ID_H264);
encode_example("tmp.mpg", AV_CODEC_ID_MPEG1VIDEO);
return 0;
}
Derleme ve birlikte çalıştırın:
gcc -std=c99 -Wextra a.c -lavcodec -lswscale -lavutil
./a.out
ffplay tmp.mpg
ffplay tmp.h264
Ubuntu 16.04 üzerinde test edilmiştir.
GitHub upstream.
Downvoters lütfen açıklayın, böylece içeriği öğrenebilir ve geliştirebilirim :-) –
Bu, nvcuda.dll ve onun bağımlılıkları gerektirir. Koşmak için alınamadı. – rosewater
@rosewater rapor için teşekkürler. Nasıl kurulacağını öğrenirseniz bana bildirin. Sadece Ubuntu'da test edebilirim. –
- 1. Matplotlib'de çeşitli lekeler kullanarak bir görüntüyü klipsleyin
- 2. Bir CSV Dosyasından Nesne C Kullanarak Bir Dizi Oluşturma
- 3. Windows API kullanarak C++'da Nasıl Oynanır?
- 4. PDF kullanarak görüntüyü ayıklayın. Net C#
- 5. C++: boost :: property_tree kullanarak nasıl bir dizi oluşturulur?
- 6. Otomasyon kullanarak C++ dilinde bir dizi Excel sütununu nasıl yinelemeli?
- 7. PHP kullanarak bir görüntüyü doğrudan nasıl görüntüleyebilirim?
- 8. C# linq - farklı bir dizi
- 9. openCV kullanarak bir görüntüyü diğerinden çıkarma
- 10. Görüntüyü nesnel c nasıl kırpılır?
- 11. nasıl C API
- 12. nasıl C# Youtube API kullanarak YouYuBe bir video yükleyebilirsiniz?
- 13. Görüntüyü belirli bir noktada görüntüyü imagemagick kullanarak ekleyin
- 14. Metin altında görüntüyü iText kullanarak pdf arkaplanı olarak nasıl eklenir?
- 15. COM kullanarak bir dizi geçiriliyor?
- 16. C++ API nasıl çağırılır C#
- 17. Rastgele dizi kullanarak LINQ ve C#
- 18. JSTL kullanarak bir dizi dizi ArrayL yineleme nasıl?
- 19. Görüntüyü css kullanarak döndürme
- 20. Montaj dilinde basit kodlar
- 21. Döngü kullanarak bir Dosyadan Dizi Verilerinin Görüntülenmesi [C++]
- 22. Python C API: Bir C uzantısından
- 23. Bir dizi dizi ve dizge nasıl sıralanır?
- 24. CSS stilini kullanarak iki görüntüyü nasıl örtüşebiliriz?
- 25. ImageMagick'i kullanarak iki görüntüyü nasıl arayabilirim?
- 26. obj-c base64 görüntüyü dönüştürmek için nasıl
- 27. Görüntüyü döndürme ve görüntüyü kaydetme
- 28. C# bir dizi kontrol yaratın
- 29. Jquery döndürme eklentisini kullanarak görüntüyü nasıl döndürürsünüz?
- 30. Başlatıcı listesini kullanarak dizi öğeleri nasıl başlatılır?
Bu çok yararlıdır (+1). Python topluluğu gerçekten bu C stili kodun bazılarını özetleyen bir sarıcıya ihtiyaç duyar. –
Bunu normal bir medya istemcisine aktarmanın kolay bir yolu var mı, bir XBMC mi, yoksa bir AVI akışı olarak mı sarılıyor? – dascandy
Bir DirectShow kaynak filtresi yazabilirsiniz. AVI, H.264 için en iyi konteynır tercihi değildir, bkz. Http://en.wikipedia.org/wiki/Comparison_of_container_formats – fishfood