1# This file is part of Xpra. 2# Copyright (C) 2017-2021 Antoine Martin <antoine@xpra.org> 3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 4# later version. See the file COPYING for details. 5 6#cython: wraparound=False 7 8import os 9import time 10import errno 11import weakref 12import platform 13from xpra.log import Logger 14log = Logger("encoder", "ffmpeg") 15 16from xpra.codecs.codec_constants import video_spec 17from xpra.codecs.libav_common.av_log cimport override_logger, restore_logger, av_error_str #@UnresolvedImport pylint: disable=syntax-error 18from xpra.codecs.libav_common.av_log import SilenceAVWarningsContext # @UnresolvedImport 19from xpra.util import AtomicInteger, csv, print_nested_dict, reverse_dict, envint, envbool, typedict 20from xpra.os_util import bytestostr, strtobytes, LINUX 21from xpra.buffers.membuf cimport memalign 22 23from libc.string cimport memset #pylint: disable=syntax-error 24from libc.stdint cimport uintptr_t, uint8_t, uint16_t, uint32_t, int64_t, uint64_t 25from libc.stdlib cimport free 26 27SAVE_TO_FILE = os.environ.get("XPRA_SAVE_TO_FILE") 28 29THREAD_TYPE = envint("XPRA_FFMPEG_THREAD_TYPE", 2) 30THREAD_COUNT= envint("XPRA_FFMPEG_THREAD_COUNT") 31AUDIO = envbool("XPRA_FFMPEG_MPEG4_AUDIO", False) 32 33 34cdef extern from "Python.h": 35 int PyObject_GetBuffer(object obj, Py_buffer *view, int flags) 36 void PyBuffer_Release(Py_buffer *view) 37 int PyBUF_ANY_CONTIGUOUS 38 39cdef extern from "libavutil/mem.h": 40 void av_free(void *ptr) 41 void *av_malloc(size_t size) 42 43cdef extern from "libavcodec/version.h": 44 int LIBAVCODEC_VERSION_MAJOR 45 int LIBAVCODEC_VERSION_MINOR 46 int LIBAVCODEC_VERSION_MICRO 47 48#why can't we define this inside the avcodec.h section? (beats me) 49ctypedef unsigned int AVCodecID 50ctypedef long AVPixelFormat 51ctypedef long AVSampleFormat 52ctypedef int AVPictureType 53 54 55cdef extern from "libavutil/avutil.h": 56 int AV_PICTURE_TYPE_NONE 57 int AV_PICTURE_TYPE_I 58 int AV_PICTURE_TYPE_P 59 int AV_PICTURE_TYPE_B 60 int AV_PICTURE_TYPE_S 61 int AV_PICTURE_TYPE_SI 62 int AV_PICTURE_TYPE_SP 63 int AV_PICTURE_TYPE_BI 64 65cdef extern from "libavutil/dict.h": 66 int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags) 67 int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags) 68 void av_dict_free(AVDictionary **m) 69 70cdef extern from "libavutil/pixfmt.h": 71 AVPixelFormat AV_PIX_FMT_NONE 72 AVPixelFormat AV_PIX_FMT_YUV420P 73 AVPixelFormat AV_PIX_FMT_YUV422P 74 AVPixelFormat AV_PIX_FMT_YUV444P 75 AVPixelFormat AV_PIX_FMT_RGB24 76 AVPixelFormat AV_PIX_FMT_0RGB 77 AVPixelFormat AV_PIX_FMT_BGR0 78 AVPixelFormat AV_PIX_FMT_ARGB 79 AVPixelFormat AV_PIX_FMT_BGRA 80 AVPixelFormat AV_PIX_FMT_GBRP 81 AVPixelFormat AV_PIX_FMT_VAAPI 82 AVPixelFormat AV_PIX_FMT_NV12 83 84cdef extern from "libavutil/samplefmt.h": 85 AVSampleFormat AV_SAMPLE_FMT_S16 86 AVSampleFormat AV_SAMPLE_FMT_FLTP 87 88 89cdef extern from "libavutil/frame.h": 90 int av_frame_get_buffer(AVFrame *frame, int align) 91 92cdef extern from "libavutil/buffer.h": 93 ctypedef struct AVBuffer: 94 pass 95 ctypedef struct AVBufferRef: 96 AVBuffer* buffer 97 uint8_t *data 98 int size 99 AVBufferRef *av_buffer_ref(AVBufferRef *buf) 100 void av_buffer_unref(AVBufferRef **buf) 101 102cdef extern from "libavformat/avio.h": 103 ctypedef int AVIODataMarkerType 104 int AVIO_FLAG_WRITE 105 106 ctypedef struct AVIOContext: 107 const AVClass *av_class 108 unsigned char *buffer #Start of the buffer 109 int buffer_size #Maximum buffer size 110 unsigned char *buf_ptr #Current position in the buffer 111 unsigned char *buf_end #End of the data, may be less than 112 #buffer+buffer_size if the read function returned 113 #less data than requested, e.g. for streams where 114 #no more data has been received yet. 115 int64_t pos #position in the file of the current buffer 116 int must_flush #true if the next seek should flush 117 int error #contains the error code or 0 if no error happened 118 int seekable 119 int64_t maxsize 120 int direct 121 int64_t bytes_read 122 123 AVIOContext *avio_alloc_context(unsigned char *buffer, int buffer_size, int write_flag, 124 void *opaque, 125 int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), 126 int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), 127 int64_t (*seek)(void *opaque, int64_t offset, int whence)) 128 129 130cdef extern from "libavcodec/avcodec.h": 131 int FF_THREAD_SLICE #allow more than one thread per frame 132 int FF_THREAD_FRAME #Decode more than one frame at once 133 134 int FF_PROFILE_H264_CONSTRAINED 135 int FF_PROFILE_H264_INTRA 136 int FF_PROFILE_H264_BASELINE 137 int FF_PROFILE_H264_CONSTRAINED_BASELINE 138 int FF_PROFILE_H264_MAIN 139 int FF_PROFILE_H264_EXTENDED 140 int FF_PROFILE_H264_HIGH 141 int FF_PROFILE_H264_HIGH_10 142 int FF_PROFILE_H264_HIGH_10_INTRA 143 int FF_PROFILE_H264_MULTIVIEW_HIGH 144 int FF_PROFILE_H264_HIGH_422 145 int FF_PROFILE_H264_HIGH_422_INTRA 146 int FF_PROFILE_H264_STEREO_HIGH 147 int FF_PROFILE_H264_HIGH_444 148 int FF_PROFILE_H264_HIGH_444_PREDICTIVE 149 int FF_PROFILE_H264_HIGH_444_INTRA 150 int FF_PROFILE_H264_CAVLC_444 151 152 int FF_PROFILE_HEVC_MAIN 153 int FF_PROFILE_HEVC_MAIN_10 154 int FF_PROFILE_HEVC_MAIN_STILL_PICTURE 155 int FF_PROFILE_HEVC_REXT 156 157 int FF_PROFILE_MPEG2_422 158 int FF_PROFILE_MPEG2_HIGH 159 int FF_PROFILE_MPEG2_SS 160 int FF_PROFILE_MPEG2_SNR_SCALABLE 161 int FF_PROFILE_MPEG2_MAIN 162 int FF_PROFILE_MPEG2_SIMPLE 163 164 int AV_CODEC_FLAG_UNALIGNED 165 int AV_CODEC_FLAG_QSCALE 166 int AV_CODEC_FLAG_4MV 167 int AV_CODEC_FLAG_OUTPUT_CORRUPT 168 int AV_CODEC_FLAG_QPEL 169 int AV_CODEC_FLAG_PASS1 170 int AV_CODEC_FLAG_PASS2 171 int AV_CODEC_FLAG_GRAY 172 int AV_CODEC_FLAG_PSNR 173 int AV_CODEC_FLAG_TRUNCATED 174 int AV_CODEC_FLAG_INTERLACED_DCT 175 int AV_CODEC_FLAG_GLOBAL_HEADER 176 177 int AV_CODEC_FLAG2_FAST 178 179 int AV_CODEC_CAP_DRAW_HORIZ_BAND 180 int AV_CODEC_CAP_DR1 181 int AV_CODEC_CAP_TRUNCATED 182 int AV_CODEC_CAP_DELAY 183 int AV_CODEC_CAP_SMALL_LAST_FRAME 184 int AV_CODEC_CAP_SUBFRAMES 185 int AV_CODEC_CAP_EXPERIMENTAL 186 int AV_CODEC_CAP_CHANNEL_CONF 187 int AV_CODEC_CAP_FRAME_THREADS 188 int AV_CODEC_CAP_SLICE_THREADS 189 int AV_CODEC_CAP_PARAM_CHANGE 190 int AV_CODEC_CAP_AUTO_THREADS 191 int AV_CODEC_CAP_VARIABLE_FRAME_SIZE 192 int AV_CODEC_CAP_INTRA_ONLY 193 int AV_CODEC_CAP_LOSSLESS 194 195 ctypedef struct AVFrame: 196 uint8_t **data 197 int *linesize 198 int width 199 int height 200 int format 201 int key_frame 202 int64_t pts 203 int coded_picture_number 204 int display_picture_number 205 int quality 206 void *opaque 207 AVPictureType pict_type 208 AVDictionary *metadata 209 AVBufferRef *hw_frames_ctx 210 ctypedef struct AVCodec: 211 int capabilities 212 const char *name 213 const char *long_name 214 ctypedef struct AVDictionary: 215 pass 216 int AV_PKT_FLAG_KEY 217 int AV_PKT_FLAG_CORRUPT 218 ctypedef struct AVPacket: 219 int64_t pts 220 int64_t dts 221 uint8_t *data 222 int size 223 int stream_index 224 int flags 225 int64_t duration 226 int64_t pos 227 228 ctypedef struct AVRational: 229 int num 230 int den 231 232 ctypedef int AVMediaType 233 ctypedef struct AVCodecContext: 234 const AVClass *av_class 235 int log_level_offset 236 AVMediaType codec_type 237 AVCodec *codec 238 AVCodecID codec_id 239 unsigned int codec_tag 240 void *priv_data 241 void *internal 242 void *opaque 243 int64_t bit_rate 244 int bit_rate_tolerance 245 int global_quality 246 int compression_level 247 int flags 248 int flags2 249 uint8_t *extradata 250 int extradata_size 251 AVRational time_base 252 int ticks_per_frame 253 int delay 254 int width 255 int height 256 int coded_width 257 int coded_height 258 int gop_size 259 AVPixelFormat pix_fmt 260 #some functions omitted here 261 int max_b_frames 262 float b_quant_factor 263 float b_quant_offset 264 int has_b_frames 265 int i_quant_factor 266 float i_quant_offset 267 float lumi_masking 268 float temporal_cplx_masking 269 float spatial_cplx_masking 270 float p_masking 271 float dark_masking 272 int slice_count 273 int slice_offset 274 AVRational sample_aspect_ratio 275 int me_cmp 276 int me_sub_cmp 277 int mb_cmp 278 int ildct_cmp 279 int dia_size 280 int last_predictor_count 281 int me_pre_cmp 282 int pre_dia_size 283 int me_subpel_quality 284 int me_range 285 int slice_flags 286 int mb_decision 287 uint16_t *intra_matrix 288 uint16_t *inter_matrix 289 int intra_dc_precision 290 int skip_top 291 int skip_bottom 292 int mb_lmin 293 int mb_lmax 294 int bidir_refine 295 int keyint_mint 296 int refs 297 int mv0_threshold 298 #skipped: AVColor* 299 int slices 300 int sample_rate 301 int channels 302 AVSampleFormat sample_fmt 303 int frame_size 304 int frame_number 305 int block_align 306 int cutoff 307 uint64_t channel_layout 308 uint64_t request_channel_layout 309 #skippped: AVAudioServiceType 310 # AVSampleFormat 311 int refcounted_frames 312 float qcompress 313 float qblur 314 int qmin 315 int qmax 316 int max_qdiff 317 int rc_buffer_size 318 int rc_override_count 319 int64_t rc_max_rate 320 int64_t rc_min_rate 321 float rc_max_available_vbv_use 322 float rc_min_vbv_overflow_use 323 int rc_initial_buffer_occupancy 324 int strict_std_compliance 325 int error_concealment 326 int debug 327 int debug_mv 328 int err_recognition 329 int thread_count 330 int thread_type 331 int active_thread_type 332 #int thread_safe_callbacks 333 int profile 334 int level 335 AVRational framerate 336 AVBufferRef *hw_frames_ctx 337 338 ctypedef struct AVFormatContext: 339 const AVClass *av_class 340 AVOutputFormat *oformat 341 void *priv_data 342 AVIOContext *pb 343 int ctx_flags 344 unsigned int nb_streams 345 AVStream **streams 346 int64_t start_time 347 int64_t duration 348 int bit_rate 349 unsigned int packet_size 350 int max_delay 351 int flags 352 unsigned int probesize 353 int max_analyze_duration 354 AVCodecID video_codec_id 355 AVCodecID audio_codec_id 356 AVCodecID subtitle_codec_id 357 unsigned int max_index_size 358 unsigned int max_picture_buffer 359 unsigned int nb_chapters 360 AVDictionary *metadata 361 int64_t start_time_realtime 362 int strict_std_compliance 363 int flush_packets 364 365 ctypedef int AVFieldOrder 366 ctypedef int AVColorRange 367 ctypedef int AVColorPrimaries 368 ctypedef int AVColorTransferCharacteristic 369 ctypedef int AVColorSpace 370 ctypedef int AVChromaLocation 371 ctypedef struct AVCodecParameters: 372 AVCodecID codec_id 373 uint32_t codec_tag 374 int64_t bit_rate 375 int bits_per_coded_sample 376 int bits_per_raw_sample 377 int profile 378 int level 379 int width 380 int height 381 AVFieldOrder field_order 382 AVColorRange color_range 383 AVColorPrimaries color_primaries 384 AVColorTransferCharacteristic color_trc 385 AVColorSpace color_space 386 AVChromaLocation chroma_location 387 int sample_rate 388 int frame_size 389 390 AVCodecID AV_CODEC_ID_H264 391 AVCodecID AV_CODEC_ID_H265 392 AVCodecID AV_CODEC_ID_VP8 393 AVCodecID AV_CODEC_ID_VP9 394 AVCodecID AV_CODEC_ID_MPEG4 395 AVCodecID AV_CODEC_ID_MPEG1VIDEO 396 AVCodecID AV_CODEC_ID_MPEG2VIDEO 397 398 AVCodecID AV_CODEC_ID_AAC 399 400 #init and free: 401 AVCodec *avcodec_find_encoder(AVCodecID id) 402 AVCodecContext *avcodec_alloc_context3(const AVCodec *codec) 403 int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options) 404 int avcodec_send_frame(AVCodecContext *avctx,const AVFrame *frame) nogil 405 int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) nogil 406 407 AVFrame* av_frame_alloc() 408 void av_frame_free(AVFrame **frame) 409 int avcodec_close(AVCodecContext *avctx) 410 void av_frame_unref(AVFrame *frame) nogil 411 412 AVPacket *av_packet_alloc() nogil 413 void av_packet_free(AVPacket **avpkt) 414 415 void avcodec_free_context(AVCodecContext **avctx) 416 const AVCodec *avcodec_find_encoder_by_name(const char *name) 417 418ctypedef int AVOptionType 419cdef extern from "libavutil/opt.h": 420 AVOptionType AV_OPT_TYPE_FLAGS 421 AVOptionType AV_OPT_TYPE_INT 422 AVOptionType AV_OPT_TYPE_INT64 423 AVOptionType AV_OPT_TYPE_DOUBLE 424 AVOptionType AV_OPT_TYPE_FLOAT 425 AVOptionType AV_OPT_TYPE_STRING 426 AVOptionType AV_OPT_TYPE_RATIONAL 427 AVOptionType AV_OPT_TYPE_BINARY #offset must point to a pointer immediately followed by an int for the length 428 AVOptionType AV_OPT_TYPE_DICT 429 AVOptionType AV_OPT_TYPE_CONST 430 AVOptionType AV_OPT_TYPE_IMAGE_SIZE 431 AVOptionType AV_OPT_TYPE_PIXEL_FMT 432 AVOptionType AV_OPT_TYPE_SAMPLE_FMT 433 AVOptionType AV_OPT_TYPE_VIDEO_RATE 434 AVOptionType AV_OPT_TYPE_DURATION 435 AVOptionType AV_OPT_TYPE_COLOR 436 AVOptionType AV_OPT_TYPE_CHANNEL_LAYOUT 437 AVOptionType AV_OPT_TYPE_BOOL 438 439 int AV_OPT_SEARCH_CHILDREN 440 int AV_OPT_SEARCH_FAKE_OBJ 441 442 ctypedef struct AVOption: 443 const char *name #short English help text 444 const char *help 445 int offset #The offset relative to the context structure where the option value is stored. It should be 0 for named constants. 446 AVOptionType type 447 int flags 448 const char *unit 449 450 const AVOption* av_opt_next(void *obj, const AVOption *prev) 451 void *av_opt_child_next(void *obj, void *prev) 452 int av_opt_set(void *obj, const char *name, const char *val, int search_flags) 453 int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags) 454 int av_opt_get_int(void *obj, const char *name, int search_flags, int64_t *out_val) 455 int av_opt_set_dict(void *obj, AVDictionary **options) 456 457 458cdef extern from "libavutil/log.h": 459 ctypedef struct AVClass: 460 const char *class_name #The name of the class; usually it is the same name as the context structure type to which the AVClass is associated. 461 const char *(*item_name)(void *ctx) #A pointer to a function which returns the name of a context instance ctx associated with the class. 462 AVOption *option #a pointer to the first option specified in the class if any or NULL 463 int version #LIBAVUTIL_VERSION with which this structure was created 464 int log_level_offset_offset #Offset in the structure where log_level_offset is stored 465 int parent_log_context_offset #Offset in the structure where a pointer to the parent context for logging is stored 466 void *(*child_next)(void *obj, void *prev) #Return next AVOptions-enabled child or NULL 467 AVClass *(*child_class_next)(const AVClass *prev) #Return an AVClass corresponding to the next potential AVOptions-enabled child. 468 #AVClassCategory category #Category used for visualization (like color) This is only set if the category is equal for all objects using this class. 469 #AVClassCategory (*get_category)(void *ctx) 470 471 472cdef extern from "libavformat/avformat.h": 473 int AVFMTCTX_NOHEADER #signal that no header is present 474 475 int AVFMT_FLAG_GENPTS #Generate missing pts even if it requires parsing future frames 476 int AVFMT_FLAG_IGNIDX #Ignore index 477 int AVFMT_FLAG_NONBLOCK #Do not block when reading packets from input 478 int AVFMT_FLAG_IGNDTS #Ignore DTS on frames that contain both DTS & PTS 479 int AVFMT_FLAG_NOFILLIN #Do not infer any values from other values, just return what is stored in the container 480 int AVFMT_FLAG_NOPARSE #Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. Also seeking to frames can not work if parsing to find frame boundaries has been disabled 481 int AVFMT_FLAG_NOBUFFER #Do not buffer frames when possible 482 int AVFMT_FLAG_CUSTOM_IO #The caller has supplied a custom AVIOContext, don't avio_close() it 483 int AVFMT_FLAG_DISCARD_CORRUPT #Discard frames marked corrupted 484 int AVFMT_FLAG_FLUSH_PACKETS #Flush the AVIOContext every packet 485 int AVFMT_FLAG_BITEXACT 486 int AVFMT_FLAG_SORT_DTS #try to interleave outputted packets by dts (using this flag can slow demuxing down) 487 int AVFMT_FLAG_PRIV_OPT #Enable use of private options by delaying codec open (this could be made default once all code is converted) 488 int AVFMT_FLAG_FAST_SEEK #Enable fast, but inaccurate seeks for some formats 489 490 int AVFMT_NOFILE #Demuxer will use avio_open, no opened file should be provided by the caller 491 int AVFMT_NEEDNUMBER #Needs '%d' in filename 492 int AVFMT_SHOW_IDS #Show format stream IDs numbers 493 int AVFMT_GLOBALHEADER #Format wants global header 494 int AVFMT_NOTIMESTAMPS #Format does not need / have any timestamps 495 int AVFMT_GENERIC_INDEX #Use generic index building code 496 int AVFMT_TS_DISCONT #Format allows timestamp discontinuities. Note, muxers always require valid (monotone) timestamps 497 int AVFMT_VARIABLE_FPS #Format allows variable fps 498 int AVFMT_NODIMENSIONS #Format does not need width/height 499 int AVFMT_NOSTREAMS #Format does not require any streams 500 int AVFMT_NOBINSEARCH #Format does not allow to fall back on binary search via read_timestamp 501 int AVFMT_NOGENSEARCH #Format does not allow to fall back on generic search 502 int AVFMT_NO_BYTE_SEEK #Format does not allow seeking by bytes 503 int AVFMT_ALLOW_FLUSH #Format allows flushing. If not set, the muxer will not receive a NULL packet in the write_packet function 504 int AVFMT_TS_NONSTRICT #Format does not require strictly increasing timestamps, but they must still be monotonic 505 int AVFMT_TS_NEGATIVE #Format allows muxing negative timestamps. 506 int AVFMT_SEEK_TO_PTS #Seeking is based on PTS 507 508 ctypedef struct AVStream: 509 int index #stream index in AVFormatContext 510 int id 511 AVCodecContext *codec 512 AVRational time_base 513 int64_t start_time 514 int64_t duration 515 int64_t nb_frames #number of frames in this stream if known or 0 516 #AVDiscard discard #Selects which packets can be discarded at will and do not need to be demuxed. 517 AVRational avg_frame_rate 518 AVCodecParameters *codecpar 519 520 ctypedef struct AVOutputFormat: 521 const char *name 522 const char *long_name 523 const char *mime_type 524 const char *extensions 525 AVCodecID audio_codec 526 AVCodecID video_codec 527 AVCodecID subtitle_codec 528 int flags #AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS, AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH, AVFMT_TS_NONSTRICT, AVFMT_TS_NEGATIVE More... 529 int (*query_codec)(AVCodecID id, int std_compliance) 530 531 const AVOutputFormat *av_muxer_iterate(void **opaque) 532 int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, const char *format_name, const char *filename) 533 void avformat_free_context(AVFormatContext *s) 534 535 int avcodec_parameters_from_context(AVCodecParameters *par, const AVCodecContext *codec) 536 AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) 537 int avformat_write_header(AVFormatContext *s, AVDictionary **options) 538 int av_write_trailer(AVFormatContext *s) 539 int av_write_frame(AVFormatContext *s, AVPacket *pkt) 540 int av_frame_make_writable(AVFrame *frame) 541 542 543cdef extern from "libavutil/hwcontext.h": 544 ctypedef int AVHWDeviceType 545 int AV_HWDEVICE_TYPE_NONE 546 int AV_HWDEVICE_TYPE_VDPAU 547 int AV_HWDEVICE_TYPE_CUDA 548 int AV_HWDEVICE_TYPE_VAAPI 549 int AV_HWDEVICE_TYPE_DXVA2 550 int AV_HWDEVICE_TYPE_QSV 551 int AV_HWDEVICE_TYPE_VIDEOTOOLBOX 552 int AV_HWDEVICE_TYPE_D3D11VA 553 int AV_HWDEVICE_TYPE_DRM 554 int AV_HWDEVICE_TYPE_OPENCL 555 int AV_HWDEVICE_TYPE_MEDIACODEC 556 557 ctypedef struct AVHWDeviceContext: 558 const AVClass av_class 559 #AVHWDeviceType type 560 561 ctypedef struct AVHWFramesContext: 562 const AVClass av_class 563 AVBufferRef device_ref 564 AVHWDeviceContext *device_ctx 565 void *hwctx 566 void *user_opaque 567 int initial_pool_size 568 AVPixelFormat format 569 AVPixelFormat sw_format 570 int width 571 int height 572 573 AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ctx) 574 int av_hwframe_ctx_init(AVBufferRef *ref) 575 int av_hwdevice_ctx_create(AVBufferRef **device_ctx, AVHWDeviceType type, 576 const char *device, AVDictionary *opts, int flags) 577 int av_hwframe_get_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame, int flags) 578 int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags) 579 580 581H264_PROFILE_NAMES = { 582 FF_PROFILE_H264_CONSTRAINED : "constrained", 583 FF_PROFILE_H264_INTRA : "intra", 584 FF_PROFILE_H264_BASELINE : "baseline", 585 FF_PROFILE_H264_CONSTRAINED_BASELINE : "constrained baseline", 586 FF_PROFILE_H264_MAIN : "main", 587 FF_PROFILE_H264_EXTENDED : "extended", 588 FF_PROFILE_H264_HIGH : "high", 589 FF_PROFILE_H264_HIGH_10 : "high10", 590 FF_PROFILE_H264_HIGH_10_INTRA : "high10 intra", 591 FF_PROFILE_H264_MULTIVIEW_HIGH : "multiview high", 592 FF_PROFILE_H264_HIGH_422 : "high422", 593 FF_PROFILE_H264_HIGH_422_INTRA : "high422 intra", 594 FF_PROFILE_H264_STEREO_HIGH : "stereo high", 595 FF_PROFILE_H264_HIGH_444 : "high444", 596 FF_PROFILE_H264_HIGH_444_PREDICTIVE : "high444 predictive", 597 FF_PROFILE_H264_HIGH_444_INTRA : "high444 intra", 598 FF_PROFILE_H264_CAVLC_444 : "cavlc 444", 599 } 600H264_PROFILES = reverse_dict(H264_PROFILE_NAMES) 601 602HEVC_PROFILE_NAMES = { 603 FF_PROFILE_HEVC_MAIN : "main", 604 FF_PROFILE_HEVC_MAIN_10 : "main10", 605 FF_PROFILE_HEVC_MAIN_STILL_PICTURE : "picture", 606 FF_PROFILE_HEVC_REXT : "rext", 607 } 608HEVC_PROFILES = reverse_dict(HEVC_PROFILE_NAMES) 609 610MPEG2_PROFILE_NAMES = { 611 FF_PROFILE_MPEG2_422 : "422", 612 FF_PROFILE_MPEG2_HIGH : "high", 613 FF_PROFILE_MPEG2_SS : "ss", 614 FF_PROFILE_MPEG2_SNR_SCALABLE : "snr-scalable", 615 FF_PROFILE_MPEG2_MAIN : "main", 616 FF_PROFILE_MPEG2_SIMPLE : "simple", 617 } 618MPEG2_PROFILES = reverse_dict(MPEG2_PROFILE_NAMES) 619 620PROFILES = { 621 "h264" : H264_PROFILES, 622 "hevc" : HEVC_PROFILES, 623 "mpeg2" : MPEG2_PROFILES, 624 } 625 626DEFAULT_PROFILE = { 627 "h264" : "main", 628 "hevc" : "main", 629 "mpeg" : "main", 630 } 631 632 633AV_OPT_TYPES = { 634 AV_OPT_TYPE_FLAGS : "FLAGS", 635 AV_OPT_TYPE_INT : "INT", 636 AV_OPT_TYPE_INT64 : "INT64", 637 AV_OPT_TYPE_DOUBLE : "DOUBLE", 638 AV_OPT_TYPE_FLOAT : "FLOAT", 639 AV_OPT_TYPE_STRING : "STRING", 640 AV_OPT_TYPE_RATIONAL : "RATIONAL", 641 AV_OPT_TYPE_BINARY : "BINARY", 642 AV_OPT_TYPE_DICT : "DICT", 643 AV_OPT_TYPE_CONST : "CONST", 644 AV_OPT_TYPE_IMAGE_SIZE : "IMAGE_SIZE", 645 AV_OPT_TYPE_PIXEL_FMT : "PIXEL_FMT", 646 AV_OPT_TYPE_SAMPLE_FMT : "SAMPLE_FMT", 647 AV_OPT_TYPE_VIDEO_RATE : "VIDEO_RATE", 648 AV_OPT_TYPE_DURATION : "DURATION", 649 AV_OPT_TYPE_COLOR : "COLOR", 650 AV_OPT_TYPE_CHANNEL_LAYOUT : "CHANNEL_LAYOUT", 651 AV_OPT_TYPE_BOOL : "BOOL", 652 } 653 654 655PKT_FLAGS = { 656 AV_PKT_FLAG_KEY : "KEY", 657 AV_PKT_FLAG_CORRUPT : "CORRUPT", 658 } 659 660AVFMTCTX = { 661 AVFMTCTX_NOHEADER : "NOHEADER", 662 } 663 664CODEC_FLAGS = { 665 AV_CODEC_FLAG_UNALIGNED : "UNALIGNED", 666 AV_CODEC_FLAG_QSCALE : "QSCALE", 667 AV_CODEC_FLAG_4MV : "4MV", 668 AV_CODEC_FLAG_OUTPUT_CORRUPT : "OUTPUT_CORRUPT", 669 AV_CODEC_FLAG_QPEL : "QPEL", 670 AV_CODEC_FLAG_PASS1 : "PASS1", 671 AV_CODEC_FLAG_PASS2 : "PASS2", 672 AV_CODEC_FLAG_GRAY : "GRAY", 673 AV_CODEC_FLAG_PSNR : "PSNR", 674 AV_CODEC_FLAG_TRUNCATED : "TRUNCATED", 675 AV_CODEC_FLAG_INTERLACED_DCT : "INTERLACED_DCT", 676 AV_CODEC_FLAG_GLOBAL_HEADER : "GLOBAL_HEADER", 677 } 678 679CODEC_FLAGS2 = { 680 AV_CODEC_FLAG2_FAST : "FAST", 681 } 682 683FMT_FLAGS = { 684 AVFMT_FLAG_GENPTS : "GENPTS", 685 AVFMT_FLAG_IGNIDX : "IGNIDX", 686 AVFMT_FLAG_NONBLOCK : "NONBLOCK", 687 AVFMT_FLAG_IGNDTS : "IGNDTS", 688 AVFMT_FLAG_NOFILLIN : "NOFILLIN", 689 AVFMT_FLAG_NOPARSE : "NOPARSE", 690 AVFMT_FLAG_NOBUFFER : "NOBUFFER", 691 AVFMT_FLAG_CUSTOM_IO : "CUSTOM_IO", 692 AVFMT_FLAG_DISCARD_CORRUPT : "DISCARD_CORRUPT", 693 AVFMT_FLAG_FLUSH_PACKETS : "FLUSH_PACKETS", 694 AVFMT_FLAG_BITEXACT : "BITEXACT", 695 AVFMT_FLAG_SORT_DTS : "SORT_DTS", 696 AVFMT_FLAG_PRIV_OPT : "PRIV_OPT", 697 AVFMT_FLAG_FAST_SEEK : "FAST_SEEK", 698 } 699 700AVFMT = { 701 AVFMT_NOFILE : "NOFILE", 702 AVFMT_NEEDNUMBER : "NEEDNUMBER", 703 AVFMT_SHOW_IDS : "SHOW_IDS", 704 AVFMT_GLOBALHEADER : "GLOBALHEADER", 705 AVFMT_NOTIMESTAMPS : "NOTIMESTAMPS", 706 AVFMT_GENERIC_INDEX : "GENERIC_INDEX", 707 AVFMT_TS_DISCONT : "TS_DISCONT", 708 AVFMT_VARIABLE_FPS : "VARIABLE_FPS", 709 AVFMT_NODIMENSIONS : "NODIMENSIONS", 710 AVFMT_NOSTREAMS : "NOSTREAMS", 711 AVFMT_NOBINSEARCH : "NOBINSEARCH", 712 AVFMT_NOGENSEARCH : "NOGENSEARCH", 713 AVFMT_NO_BYTE_SEEK : "NO_BYTE_SEEK", 714 AVFMT_ALLOW_FLUSH : "ALLOW_FLUSH", 715 AVFMT_TS_NONSTRICT : "TS_NONSTRICT", 716 AVFMT_TS_NEGATIVE : "TS_NEGATIVE", 717 AVFMT_SEEK_TO_PTS : "SEEK_TO_PTS", 718 } 719 720 721CAPS = { 722 AV_CODEC_CAP_DRAW_HORIZ_BAND : "DRAW_HORIZ_BAND", 723 AV_CODEC_CAP_DR1 : "DR1", 724 AV_CODEC_CAP_TRUNCATED : "TRUNCATED", 725 AV_CODEC_CAP_DELAY : "DELAY", 726 AV_CODEC_CAP_SMALL_LAST_FRAME : "SMALL_LAST_FRAME", 727 AV_CODEC_CAP_SUBFRAMES : "SUBFRAMES", 728 AV_CODEC_CAP_EXPERIMENTAL : "EXPERIMENTAL", 729 AV_CODEC_CAP_CHANNEL_CONF : "CHANNEL_CONF", 730 AV_CODEC_CAP_FRAME_THREADS : "FRAME_THREADS", 731 AV_CODEC_CAP_SLICE_THREADS : "SLICE_THREADS", 732 AV_CODEC_CAP_PARAM_CHANGE : "PARAM_CHANGE", 733 AV_CODEC_CAP_AUTO_THREADS : "AUTO_THREADS", 734 AV_CODEC_CAP_VARIABLE_FRAME_SIZE : "VARIABLE_FRAME_SIZE", 735 AV_CODEC_CAP_INTRA_ONLY : "INTRA_ONLY", 736 AV_CODEC_CAP_LOSSLESS : "LOSSLESS", 737 } 738log("CODEC_CAP:") 739print_nested_dict(dict((hex(abs(k)),v) for k,v in CAPS.items()), print_fn=log.debug) 740 741PICTURE_TYPE = { 742 AV_PICTURE_TYPE_NONE : "NONE", 743 AV_PICTURE_TYPE_I : "I", 744 AV_PICTURE_TYPE_P : "P", 745 AV_PICTURE_TYPE_B : "B", 746 AV_PICTURE_TYPE_S : "S", 747 AV_PICTURE_TYPE_SI : "SI", 748 AV_PICTURE_TYPE_SP : "SP", 749 AV_PICTURE_TYPE_BI : "BI", 750 } 751log("AV_PICTURE:") 752print_nested_dict(PICTURE_TYPE, print_fn=log.debug) 753 754FORMAT_TO_ENUM = { 755 "YUV420P" : AV_PIX_FMT_YUV420P, 756 "YUV422P" : AV_PIX_FMT_YUV422P, 757 "YUV444P" : AV_PIX_FMT_YUV444P, 758 "RGB" : AV_PIX_FMT_RGB24, 759 "XRGB" : AV_PIX_FMT_0RGB, 760 "BGRX" : AV_PIX_FMT_BGR0, 761 "ARGB" : AV_PIX_FMT_ARGB, 762 "BGRA" : AV_PIX_FMT_BGRA, 763 "GBRP" : AV_PIX_FMT_GBRP, 764 "VAAPI" : AV_PIX_FMT_VAAPI, 765 "NV12" : AV_PIX_FMT_NV12, 766 } 767 768CODEC_ID = { 769 "h264" : AV_CODEC_ID_H264, 770 "h265" : AV_CODEC_ID_H265, 771 "vp8" : AV_CODEC_ID_VP8, 772 "vp9" : AV_CODEC_ID_VP9, 773 "mpeg4" : AV_CODEC_ID_MPEG4, 774 "mpeg1" : AV_CODEC_ID_MPEG1VIDEO, 775 "mpeg2" : AV_CODEC_ID_MPEG2VIDEO, 776 } 777 778COLORSPACES = FORMAT_TO_ENUM.keys() 779ENUM_TO_FORMAT = {} 780for pix_fmt, av_enum in FORMAT_TO_ENUM.items(): 781 ENUM_TO_FORMAT[av_enum] = pix_fmt 782log("AV_PIX_FMT:") 783print_nested_dict(ENUM_TO_FORMAT, print_fn=log.debug) 784 785def flagscsv(flag_dict, value=0): 786 return csv([bytestostr(v) for k,v in flag_dict.items() if k&value]) 787 788 789def get_muxer_formats(): 790 cdef AVOutputFormat *fmt 791 cdef void *opaque = NULL 792 formats = {} 793 while True: 794 fmt = <AVOutputFormat*> av_muxer_iterate(&opaque) 795 if fmt==NULL: 796 break 797 name = bytestostr(fmt.name) 798 long_name = bytestostr(fmt.long_name) 799 formats[name] = bytestostr(long_name) 800 return formats 801log("AV Output Formats:") 802print_nested_dict(get_muxer_formats(), print_fn=log.debug) 803 804cdef AVOutputFormat* get_av_output_format(name): 805 cdef AVOutputFormat *fmt 806 cdef void *opaque = NULL 807 while True: 808 fmt = <AVOutputFormat*> av_muxer_iterate(&opaque) 809 if fmt==NULL: 810 break 811 if bytestostr(name)==bytestostr(fmt.name): 812 return fmt 813 return NULL 814 815 816def get_version(): 817 return (LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO) 818 819 820VAAPI = envbool("XPRA_VAAPI", LINUX and (LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR)>=(4, 4) and platform.release()>="5.") 821 822CODECS = () 823 824DEF DEFAULT_BUF_LEN = 64*1024 825 826 827VAAPI_CODECS = [] 828 829ENCODER_NAMES = { 830 "h264" : b"libx264", 831 "vp8" : b"libvpx", 832 "vp9" : b"libvpx", 833 "mpeg1" : b"mpeg1video", 834 "mpeg2" : b"mpeg2video", 835 } 836 837 838def init_module(): 839 global CODECS 840 log("enc_ffmpeg.init_module()") 841 override_logger() 842 all_codecs = [] 843 for codec_id, codecs in { 844 AV_CODEC_ID_H264 : ("h264+mp4", ), #"h264" 845 #AV_CODEC_ID_VP8 : ("vp8", "vp8+webm"), 846 #AV_CODEC_ID_VP9 : ("vp9", "vp9+webm"), 847 #AV_CODEC_ID_H265 : ("h265"), 848 AV_CODEC_ID_MPEG4 : ("mpeg4+mp4", ), 849 AV_CODEC_ID_MPEG1VIDEO : ("mpeg1", ), 850 AV_CODEC_ID_MPEG2VIDEO : ("mpeg2", ) 851 }.items(): 852 if avcodec_find_encoder(codec_id): 853 all_codecs += codecs 854 else: 855 log("cannot find encoder %i for %s", codec_id, csv(codecs)) 856 log("enc_ffmpeg non vaapi CODECS=%s", csv(all_codecs)) 857 if VAAPI and LINUX: 858 with SilenceAVWarningsContext(): 859 try: 860 vaapi_codecs = init_vaapi() 861 for c in vaapi_codecs: 862 if c not in all_codecs: 863 all_codecs.append(c) 864 except Exception as e: 865 log("no vappi support", exc_info=True) 866 log.warn("Warning: no VAAPI support") 867 log.warn(" %s", e) 868 CODECS = tuple(all_codecs) 869 870VAAPI_ENCODINGS = os.environ.get("XPRA_VAAPI_ENCODINGS", "h264,hevc,mpeg2,vp8,vp9").split(",") 871 872def init_vaapi(): 873 global VAAPI_CODECS 874 #can we find a device: 875 cdef AVBufferRef *hw_device_ctx = init_vaapi_device() 876 cdef AVCodecContext *avctx 877 cdef const AVCodec *codec 878 cdef AVFrame *sw_frame 879 cdef AVFrame *hw_frame 880 cdef int WIDTH = 640 881 cdef int HEIGHT = 480 882 for c in VAAPI_ENCODINGS: 883 if c in VAAPI_CODECS: 884 continue 885 name = ("%s_vaapi" % c).encode("latin1") 886 codec = avcodec_find_encoder_by_name(name) 887 log("testing %s_vaapi=%#x", c, <uintptr_t> codec) 888 if not codec: 889 continue 890 #now verify we can use this codec with the device selected: 891 avctx = avcodec_alloc_context3(codec) 892 if avctx==NULL: 893 log.error("Error: failed to allocate codec context") 894 break 895 log("%s_vaapi options:", c) 896 list_options(avctx, avctx.av_class) 897 avctx.width = WIDTH 898 avctx.height = HEIGHT 899 avctx.global_quality = 20 900 avctx.framerate.num = 25 901 avctx.framerate.den = 1 902 avctx.time_base.num = 1 903 avctx.time_base.den = 25 904 avctx.sample_aspect_ratio.num = 1 905 avctx.sample_aspect_ratio.den = 1 906 avctx.pix_fmt = AV_PIX_FMT_VAAPI 907 #test encode a frame: 908 try: 909 err = set_hwframe_ctx(avctx, hw_device_ctx, WIDTH, HEIGHT) 910 log("set_hwframe_ctx(%#x, %#x, %i, %i)=%i", <uintptr_t> avctx, <uintptr_t> hw_device_ctx, WIDTH, HEIGHT, err) 911 if err<0: 912 log("failed to set hwframe context") 913 log.warn(" %s", av_error_str(err)) 914 continue 915 err = avcodec_open2(avctx, codec, NULL) 916 log("avcodec_open2(%#x, %i, NULL)=%i", <uintptr_t> avctx, <uintptr_t> codec, err) 917 if err<0: 918 log("failed to open video encoder codec") 919 log(" %i: %s", err, av_error_str(err)) 920 continue 921 sw_frame = av_frame_alloc() 922 log("av_frame_alloc()=%#x", <uintptr_t> sw_frame) 923 if sw_frame==NULL: 924 log.error("Error: failed to allocate a sw frame") 925 break 926 sw_frame.width = WIDTH 927 sw_frame.height = HEIGHT 928 sw_frame.format = AV_PIX_FMT_NV12 929 err = av_frame_get_buffer(sw_frame, 32) 930 log("av_frame_get_buffer(%#x, 32)=%i", <uintptr_t> sw_frame, err) 931 if err<0: 932 log.error("Error: failed to allocate sw buffer for a frame") 933 break 934 #TODO: put some real data in the frame: 935 for i in range(min(WIDTH, HEIGHT)//2): 936 (<uint8_t*> sw_frame.data[0])[i**2] = 255 937 (<uint8_t*> sw_frame.data[1])[i**2] = 255 938 #hardware side: 939 hw_frame = av_frame_alloc() 940 log("av_frame_alloc()=%#x", <uintptr_t> hw_frame) 941 if hw_frame==NULL: 942 log.error("Error: failed to allocate a hw frame") 943 break 944 err = av_hwframe_get_buffer(avctx.hw_frames_ctx, hw_frame, 0) 945 log("av_frame_get_buffer(%#x, %#x, 0)=%i", <uintptr_t> avctx.hw_frames_ctx, <uintptr_t> hw_frame, err) 946 if err<0 or hw_frame.hw_frames_ctx==NULL: 947 log.error("Error: failed to allocate a hw buffer") 948 log.error(" %s", av_error_str(err)) 949 continue 950 err = av_hwframe_transfer_data(hw_frame, sw_frame, 0) 951 log("av_hwframe_transfer_data(%#x, %#x, 0)=%i", <uintptr_t> hw_frame, <uintptr_t> sw_frame, err) 952 if err<0: 953 log.error("Error: failed to transfer frame data to surface") 954 log.error(" %s", av_error_str(err)) 955 continue 956 data = encode_frame(avctx, hw_frame) 957 log("encode_frame(%#x, %#x)=%i buffers", <uintptr_t> avctx, <uintptr_t> hw_frame, len(data)) 958 flushed = encode_frame(avctx, NULL) 959 log("encode_frame(%#x, NULL)=%i buffers", <uintptr_t> avctx, len(flushed)) 960 if not data and not flushed: 961 log("no data") 962 continue 963 if flushed: 964 data += flushed 965 log("compressed data buffer lengths: %s", csv([len(x) for x in data])) 966 finally: 967 av_frame_free(&hw_frame) 968 av_frame_free(&sw_frame) 969 avcodec_free_context(&avctx) 970 VAAPI_CODECS.append(c) 971 av_buffer_unref(&hw_device_ctx) 972 if VAAPI_CODECS: 973 log.info("found %i vaapi codecs: %s", len(VAAPI_CODECS), csv(VAAPI_CODECS)) 974 else: 975 log.info("no vaapi codecs found") 976 return VAAPI_CODECS 977 978cdef AVBufferRef *init_vaapi_device() except NULL: 979 cdef char* device = NULL 980 dev_str = os.environ.get("XPRA_VAAPI_DEVICE") 981 if dev_str: 982 device = dev_str 983 cdef AVDictionary *opts = NULL 984 cdef AVBufferRef *hw_device_ctx = NULL 985 cdef int err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, 986 device, opts, 0) 987 if err<0: 988 raise Exception("vaapi device context not found") 989 log("init_vaapi_device()=%#x", <uintptr_t> hw_device_ctx) 990 return hw_device_ctx 991 992 993cdef int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int width, int height): 994 cdef AVBufferRef *hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx) 995 if not hw_frames_ref: 996 log.error("Error: faicreate VAAPI frame context") 997 return -1 998 cdef AVHWFramesContext *frames_ctx = <AVHWFramesContext *> hw_frames_ref.data 999 frames_ctx.format = AV_PIX_FMT_VAAPI 1000 frames_ctx.sw_format = AV_PIX_FMT_NV12 1001 frames_ctx.width = width 1002 frames_ctx.height = height 1003 frames_ctx.initial_pool_size = 20 1004 cdef int err = av_hwframe_ctx_init(hw_frames_ref) 1005 if err<0: 1006 log.error("Error: failed to initialize VAAPI frame context") 1007 log.error(" %s", av_error_str(err)) 1008 av_buffer_unref(&hw_frames_ref) 1009 return -1 1010 ctx.hw_frames_ctx = av_buffer_ref(hw_frames_ref) 1011 if ctx.hw_frames_ctx == NULL: 1012 log.error("Error: failed to allocate hw frame buffer") 1013 av_buffer_unref(&hw_frames_ref) 1014 return -1 1015 av_buffer_unref(&hw_frames_ref) 1016 return 0 1017 1018cdef encode_frame(AVCodecContext *avctx, AVFrame *frame): 1019 err = avcodec_send_frame(avctx, frame) 1020 if err<0: 1021 log.error("Error: failed to send frame to encoder") 1022 log.error(" %s", av_error_str(err)) 1023 return None 1024 cdef AVPacket * pkt = av_packet_alloc() 1025 pkt.data = NULL 1026 pkt.size = 0 1027 data = [] 1028 while True: 1029 ret = avcodec_receive_packet(avctx, pkt) 1030 if ret: 1031 break 1032 pkt.stream_index = 0 1033 data.append(pkt.data[:pkt.size]) 1034 return data 1035 1036 1037def cleanup_module(): 1038 log("enc_ffmpeg.cleanup_module()") 1039 restore_logger() 1040 1041def get_type(): 1042 return "ffmpeg" 1043 1044generation = AtomicInteger() 1045def get_info(): 1046 global generation 1047 f = {} 1048 for e in get_encodings(): 1049 f[e] = get_input_colorspaces(e) 1050 return { 1051 "version" : get_version(), 1052 "encodings" : get_encodings(), 1053 "muxers" : get_muxer_formats(), 1054 "formats" : f, 1055 "generation" : generation.get(), 1056 } 1057 1058def get_encodings(): 1059 global CODECS 1060 return CODECS 1061 1062def get_input_colorspaces(encoding): 1063 if encoding in VAAPI_CODECS: 1064 return ["NV12"] 1065 return ["YUV420P"] 1066 1067def get_output_colorspaces(encoding, csc): 1068 if encoding not in CODECS: 1069 return [] 1070 return ["YUV420P"] 1071 1072 1073GEN_TO_ENCODER = weakref.WeakValueDictionary() 1074 1075 1076cdef list_options(void *obj, const AVClass *av_class, int skip=1): 1077 if av_class==NULL: 1078 return 1079 cdef const AVOption *option = <const AVOption*> av_class.option 1080 if skip<=0: 1081 options = [] 1082 while option: 1083 oname = bytestostr(option.name) 1084 options.append(oname) 1085 option = av_opt_next(obj, option) 1086 log("%s options: %s", bytestostr(av_class.class_name), csv(options)) 1087 cdef void *child = NULL 1088 cdef const AVClass *child_class 1089 while True: 1090 child = av_opt_child_next(obj, child) 1091 if child==NULL: 1092 return 1093 child_class = (<AVClass**> child)[0] 1094 list_options(child, child_class, skip-1) 1095 1096 1097cdef int write_packet(void *opaque, uint8_t *buf, int buf_size): 1098 global GEN_TO_ENCODER 1099 encoder = GEN_TO_ENCODER.get(<uintptr_t> opaque) 1100 #log.warn("write_packet(%#x, %#x, %#x) encoder=%s", <uintptr_t> opaque, <uintptr_t> buf, buf_size, type(encoder)) 1101 if not encoder: 1102 log.error("Error: write_packet called for unregistered encoder %i!", <uintptr_t> opaque) 1103 return -1 1104 return encoder.write_packet(<uintptr_t> buf, buf_size) 1105 1106MAX_WIDTH, MAX_HEIGHT = 4096, 4096 1107def get_spec(encoding, colorspace): 1108 assert encoding in get_encodings(), "invalid encoding: %s (must be one of %s" % (encoding, get_encodings()) 1109 assert colorspace in get_input_colorspaces(encoding), "invalid colorspace: %s (must be one of %s)" % (colorspace, get_input_colorspaces(encoding)) 1110 speed = 40 1111 setup_cost = 50 1112 cpu_cost = 100 1113 gpu_cost = 0 1114 size_efficiency = 50 1115 if encoding in VAAPI_CODECS and colorspace=="NV12": 1116 speed = 100 1117 cpu_cost = 10 1118 gpu_cost = 100 1119 size_efficiency = 100 1120 return video_spec(encoding=encoding, input_colorspace=colorspace, 1121 output_colorspaces=get_output_colorspaces(encoding, colorspace), has_lossless_mode=False, 1122 codec_class=Encoder, codec_type=get_type(), 1123 quality=40, speed=speed, size_efficiency=size_efficiency, 1124 setup_cost=setup_cost, cpu_cost=cpu_cost, gpu_cost=gpu_cost, 1125 width_mask=0xFFFE, height_mask=0xFFFE, max_w=MAX_WIDTH, max_h=MAX_HEIGHT) 1126 1127 1128cdef class Encoder: 1129 """ 1130 This wraps the AVCodecContext and its configuration, 1131 """ 1132 #muxer: 1133 cdef AVFormatContext *muxer_ctx 1134 cdef AVDictionary *muxer_opts 1135 cdef unsigned char *buffer 1136 cdef object buffers 1137 cdef int64_t offset 1138 cdef object muxer_format 1139 cdef object file 1140 #video: 1141 cdef const AVCodec *video_codec 1142 cdef AVStream *video_stream 1143 cdef AVCodecContext *video_ctx 1144 cdef AVPixelFormat pix_fmt 1145 cdef object src_format 1146 cdef AVFrame *av_frame 1147 cdef unsigned long frames 1148 cdef unsigned int width 1149 cdef unsigned int height 1150 cdef uint8_t nplanes 1151 cdef object encoding 1152 cdef object profile 1153 cdef uint8_t fast_decode 1154 #audio: 1155 cdef const AVCodec *audio_codec 1156 cdef AVStream *audio_stream 1157 cdef AVCodecContext *audio_ctx 1158 cdef uint8_t ready 1159 cdef uint8_t vaapi 1160 cdef AVBufferRef *hw_device_ctx 1161 1162 cdef object __weakref__ 1163 1164 def init_context(self, encoding, unsigned int width, unsigned int height, src_format, options): 1165 global CODECS, generation 1166 assert encoding in CODECS 1167 options = options or typedict() 1168 assert options.get("scaled-width", width)==width, "ffmpeg encoder does not handle scaling" 1169 assert options.get("scaled-height", height)==height, "ffmpeg encoder does not handle scaling" 1170 self.vaapi = encoding in VAAPI_CODECS and src_format=="NV12" 1171 self.fast_decode = options.boolget("%s.fast-decode" % encoding, False) 1172 assert src_format in get_input_colorspaces(encoding), "invalid colorspace: %s" % src_format 1173 if src_format=="YUV420P": 1174 self.nplanes = 3 1175 elif src_format=="NV12": 1176 self.nplanes = 2 1177 else: 1178 raise Exception("unknown source format '%s'" % src_format) 1179 self.encoding = encoding 1180 self.muxer_format = None 1181 if encoding.find("+")>0: 1182 self.muxer_format = encoding.split("+")[1] #ie: "mpeg4+mp4" -> "mp4" #"mov", "f4v" 1183 assert self.muxer_format in ("mp4", "webm") 1184 self.width = width 1185 self.height = height 1186 self.src_format = src_format 1187 self.pix_fmt = FORMAT_TO_ENUM.get(src_format, AV_PIX_FMT_NONE) 1188 if self.pix_fmt==AV_PIX_FMT_NONE: 1189 raise Exception("invalid pixel format: %s", src_format) 1190 self.buffers = [] 1191 1192 codec = self.encoding.split("+")[0] 1193 log("init_context codec(%s)=%s, src_format=%s, vaapi=%s", encoding, codec, src_format, self.vaapi) 1194 cdef AVCodecID video_codec_id 1195 if self.vaapi: 1196 name = ("%s_vaapi" % encoding).encode("latin1") 1197 self.video_codec = avcodec_find_encoder_by_name(name) 1198 self.hw_device_ctx = init_vaapi_device() 1199 else: 1200 name = ENCODER_NAMES.get(self.encoding) 1201 if name: 1202 log("using encoder name '%s' for '%s'", name, self.encoding) 1203 self.video_codec = avcodec_find_encoder_by_name(name) 1204 else: 1205 name = self.encoding 1206 video_codec_id = CODEC_ID.get(codec, 0) #ie: AV_CODEC_ID_H264 1207 assert video_codec_id!=0, "invalid codec; %s" % self.encoding 1208 self.video_codec = avcodec_find_encoder(video_codec_id) 1209 if self.video_codec==NULL: 1210 raise Exception("codec not found for '%s'!" % bytestostr(name)) 1211 if not self.vaapi: 1212 #make sure that we don't end up using vaapi from here 1213 #if we didn't want to use it 1214 #(otherwise it will crash) 1215 video_codec_name = bytestostr(self.video_codec.name) 1216 if video_codec_name.endswith("vaapi"): 1217 raise Exception("codec '%s' would use vaapi" % self.encoding) 1218 log("%s: \"%s\", codec flags: %s", 1219 bytestostr(self.video_codec.name), bytestostr(self.video_codec.long_name), 1220 flagscsv(CAPS, self.video_codec.capabilities)) 1221 1222 cdef int quality = options.intget("quality", 50) 1223 cdef int speed = options.intget("speed", 50) 1224 cdef uintptr_t gen = generation.increase() 1225 GEN_TO_ENCODER[gen] = self 1226 try: 1227 if self.muxer_format: 1228 assert not self.vaapi 1229 self.init_muxer(gen) 1230 self.init_encoder(quality, speed, options) 1231 if AUDIO: 1232 self.init_audio() 1233 if self.muxer_format: 1234 self.write_muxer_header() 1235 if SAVE_TO_FILE is not None: 1236 if self.muxer_format: 1237 filename = SAVE_TO_FILE+"-"+self.encoding+"-"+str(gen)+".%s" % self.muxer_format 1238 else: 1239 filename = SAVE_TO_FILE+"-"+str(gen)+"."+self.encoding 1240 self.file = open(filename, 'wb') 1241 log.info("saving %s stream to %s", self.encoding, filename) 1242 except Exception: 1243 log("init_encoder(%i, %i, %s) failed", quality, speed, options, exc_info=True) 1244 self.clean() 1245 del GEN_TO_ENCODER[gen] 1246 raise 1247 else: 1248 log("enc_ffmpeg.Encoder.init_context(%s, %s, %s) self=%s", self.width, self.height, self.src_format, self.get_info()) 1249 self.ready = 1 1250 1251 def is_ready(self): 1252 return bool(self.ready) 1253 1254 def init_muxer(self, uintptr_t gen): 1255 global GEN_TO_ENCODER 1256 cdef AVOutputFormat *oformat = get_av_output_format(strtobytes(self.muxer_format)) 1257 if oformat==NULL: 1258 raise Exception("libavformat does not support %s" % self.muxer_format) 1259 log("init_muxer(%i) AVOutputFormat(%s)=%#x, flags=%s", 1260 gen, self.muxer_format, <uintptr_t> oformat, flagscsv(AVFMT, oformat.flags)) 1261 if oformat.flags & AVFMT_ALLOW_FLUSH==0: 1262 raise Exception("AVOutputFormat(%s) does not support flushing!" % self.muxer_format) 1263 r = avformat_alloc_output_context2(&self.muxer_ctx, oformat, strtobytes(self.muxer_format), NULL) 1264 if r!=0: 1265 msg = av_error_str(r) 1266 raise Exception("libavformat cannot allocate context: %s" % msg) 1267 log("init_muxer(%i) avformat_alloc_output_context2 returned %i for %s, format context=%#x, flags=%s, ctx_flags=%s", 1268 gen, r, self.muxer_format, <uintptr_t> self.muxer_ctx, 1269 flagscsv(FMT_FLAGS, self.muxer_ctx.flags), flagscsv(AVFMTCTX, self.muxer_ctx.ctx_flags)) 1270 list_options(self.muxer_ctx, self.muxer_ctx.av_class, 0) 1271 1272 movflags = b"" 1273 if self.muxer_format=="mp4": 1274 #movflags = "empty_moov+omit_tfhd_offset+frag_keyframe+default_base_moof" 1275 movflags = b"empty_moov+frag_keyframe+default_base_moof+faststart" 1276 elif self.muxer_format=="webm": 1277 movflags = b"dash+live" 1278 if movflags: 1279 r = av_dict_set(&self.muxer_opts, b"movflags", movflags, 0) 1280 if r!=0: 1281 msg = av_error_str(r) 1282 raise Exception("failed to set %s muxer 'movflags' options '%s': %s" % (self.muxer_format, movflags, msg)) 1283 1284 self.buffer = <unsigned char*> av_malloc(DEFAULT_BUF_LEN) 1285 if self.buffer==NULL: 1286 raise Exception("failed to allocate %iKB of memory" % (DEFAULT_BUF_LEN//1024)) 1287 self.muxer_ctx.pb = avio_alloc_context(self.buffer, DEFAULT_BUF_LEN, 1, <void *> gen, NULL, write_packet, NULL) 1288 if self.muxer_ctx.pb==NULL: 1289 raise Exception("libavformat failed to allocate io context") 1290 log("init_muxer(%i) saving %s stream to bitstream buffer %#x", 1291 gen, self.encoding, <uintptr_t> self.buffer) 1292 self.muxer_ctx.flush_packets = 1 1293 self.muxer_ctx.bit_rate = 250000 1294 self.muxer_ctx.start_time = 0 1295 #self.muxer_ctx.duration = 999999 1296 self.muxer_ctx.start_time_realtime = int(time.time()*1000) 1297 self.muxer_ctx.strict_std_compliance = 1 1298 1299 self.video_stream = avformat_new_stream(self.muxer_ctx, NULL) #self.video_codec 1300 self.video_stream.id = 0 1301 log("init_muxer(%i) video: avformat_new_stream=%#x, nb streams=%i", 1302 gen, <uintptr_t> self.video_stream, self.muxer_ctx.nb_streams) 1303 1304 def write_muxer_header(self): 1305 log("write_muxer_header() %s header", self.muxer_format) 1306 assert self.muxer_opts 1307 r = avformat_write_header(self.muxer_ctx, &self.muxer_opts) 1308 av_dict_free(&self.muxer_opts) 1309 if r!=0: 1310 msg = av_error_str(r) 1311 raise Exception("libavformat failed to write header: %s" % msg) 1312 1313 def init_encoder(self, int quality, int speed, options): 1314 log("init_encoder(%i, %i, %s)", quality, speed, options) 1315 self.video_ctx = avcodec_alloc_context3(self.video_codec) 1316 if self.video_ctx==NULL: 1317 raise Exception("failed to allocate video codec context!") 1318 list_options(self.video_ctx, self.video_ctx.av_class) 1319 cdef int b_frames = 0 1320 #we need a framerate.. make one up: 1321 self.video_ctx.global_quality = 20 1322 self.video_ctx.framerate.num = 25 1323 self.video_ctx.framerate.den = 1 1324 self.video_ctx.time_base.num = 1 1325 self.video_ctx.time_base.den = 25 1326 self.video_ctx.sample_aspect_ratio.num = 1 1327 self.video_ctx.sample_aspect_ratio.den = 1 1328 #self.video_ctx.refcounted_frames = 1 1329 self.video_ctx.max_b_frames = b_frames*1 1330 self.video_ctx.has_b_frames = b_frames 1331 self.video_ctx.delay = 0 1332 self.video_ctx.gop_size = 10 1333 self.video_ctx.width = self.width 1334 self.video_ctx.height = self.height 1335 self.video_ctx.bit_rate = max(200000, self.width*self.height*4) #4 bits per pixel 1336 #self.video_ctx.thread_safe_callbacks = 1 1337 1338 cdef AVDictionary *opts = NULL 1339 cdef int r 1340 if self.encoding.startswith("h") or self.encoding=="mpeg2": 1341 #these formats all have 'profile' and 'level' attributes: hevc, h264, mpeg2 1342 #ie: the client can specify the encoding option: 1343 # "encoding.h264+mpeg4.YUV420P.profile" : "main" 1344 # (the html5 client does) 1345 # lookup YUV420P because the client doesn't need to know about NV12, 1346 # which will be decoded into YUV420P.. 1347 default_profile = DEFAULT_PROFILE.get(self.encoding) 1348 profile = options.strget("%s.YUV420P.profile" % self.encoding, default_profile) 1349 profile = options.strget("%s.%s.profile" % (self.encoding, self.src_format), profile) 1350 log("init_encoder() profile=%s", profile) 1351 if profile: 1352 if self.vaapi: 1353 global PROFILES 1354 profiles = PROFILES.get(self.encoding, {}) 1355 v = profiles.get(profile, None) 1356 if v is not None: 1357 r = av_dict_set_int(&opts, b"profile", v, 0) 1358 if r==0: 1359 self.profile = profile 1360 else: 1361 log.warn("unknown profile '%s', options for %s: %s", profile, self.encoding, csv(profiles.keys()) or "none") 1362 else: 1363 av_dict_set(&opts, b"profile", strtobytes(profile), 0) 1364 self.profile = profile 1365 1366 level = 0 1367 level_str = options.strget("%s.%s.level" % (self.encoding, self.src_format), "") 1368 if level_str: 1369 try: 1370 level = int(float(level_str)*10) #ie: "2.1" -> 21 1371 except ValueError: 1372 pass 1373 if profile and profile.find("baseline")>=0: 1374 level = min(21, level) 1375 log("init_encoder() level=%s", level) 1376 if level>0: 1377 r = av_dict_set_int(&opts, b"level", level, 0) 1378 if r!=0: 1379 raise Exception("failed to set level=%i", level) 1380 1381 if self.vaapi: 1382 self.video_ctx.pix_fmt = AV_PIX_FMT_VAAPI 1383 r = set_hwframe_ctx(self.video_ctx, self.hw_device_ctx, self.width, self.height) 1384 if r<0: 1385 raise Exception("failed to set hwframe context") 1386 if self.encoding=="h264": 1387 #reach highest quality (compression_level=0) for quality>=91: 1388 self.video_ctx.compression_level = max(0, min(7, 7-quality/13)) 1389 log("init_encoder() compression_level=%s", self.video_ctx.compression_level) 1390 else: 1391 self.video_ctx.pix_fmt = self.pix_fmt 1392 if self.encoding not in ("mpeg1", "mpeg2"): 1393 self.video_ctx.thread_type = THREAD_TYPE 1394 self.video_ctx.thread_count = THREAD_COUNT #0=auto 1395 self.video_ctx.flags |= AV_CODEC_FLAG_GLOBAL_HEADER 1396 self.video_ctx.flags2 |= AV_CODEC_FLAG2_FAST #may cause "no deblock across slices" - which should be fine 1397 log("init_encoder() thread-type=%i, thread-count=%i", THREAD_TYPE, THREAD_COUNT) 1398 log("init_encoder() codec flags: %s", flagscsv(CODEC_FLAGS, self.video_ctx.flags)) 1399 log("init_encoder() codec flags2: %s", flagscsv(CODEC_FLAGS2, self.video_ctx.flags2)) 1400 if self.encoding.startswith("h264") or self.encoding.find("mpeg4")>=0: 1401 #x264 options: 1402 tunes = [b"zerolatency"] 1403 if self.fast_decode: 1404 tunes.append(b"fastdecode") 1405 r = av_dict_set(&opts, b"tune", b"+".join(tunes), 0) 1406 log("av_dict_set tune=%s returned %i", tunes, r) 1407 r = av_dict_set(&opts, b"preset", b"ultrafast", 0) 1408 log("av_dict_set preset=ultrafast returned %i", r) 1409 if self.encoding.startswith("vp"): 1410 for k,v in { 1411 "lag-in-frames" : 0, 1412 "realtime" : 1, 1413 "rc_lookahead" : 0, 1414 "error_resilient" : 0, 1415 }.items(): 1416 r = av_dict_set_int(&opts, strtobytes(k), v, 0) 1417 if r!=0: 1418 log.error("Error: failed to set video context option '%s' to %i:", k, v) 1419 log.error(" %s", av_error_str(r)) 1420 1421 r = avcodec_open2(self.video_ctx, self.video_codec, &opts) 1422 av_dict_free(&opts) 1423 if r!=0: 1424 raise Exception("could not open %s encoder context: %s" % (self.encoding, av_error_str(r))) 1425 log("init_encoder() avcodec_open2 success") 1426 1427 if self.video_stream: 1428 assert not self.vaapi 1429 r = avcodec_parameters_from_context(self.video_stream.codecpar, self.video_ctx) 1430 if r<0: 1431 raise Exception("could not copy video context parameters %#x: %s" % (<uintptr_t> self.video_stream.codecpar, av_error_str(r))) 1432 1433 self.av_frame = av_frame_alloc() 1434 if self.av_frame==NULL: 1435 raise Exception("could not allocate an AVFrame for encoding") 1436 self.frames = 0 1437 1438 def init_audio(self): 1439 self.audio_codec = avcodec_find_encoder(AV_CODEC_ID_AAC) 1440 if self.audio_codec==NULL: 1441 raise Exception("cannot find audio codec!") 1442 log("init_audio() audio_codec=%#x", <uintptr_t> self.audio_codec) 1443 self.audio_stream = avformat_new_stream(self.muxer_ctx, NULL) 1444 self.audio_stream.id = 1 1445 log("init_audio() audio: avformat_new_stream=%#x, nb streams=%i", <uintptr_t> self.audio_stream, self.muxer_ctx.nb_streams) 1446 self.audio_ctx = avcodec_alloc_context3(self.audio_codec) 1447 log("init_audio() audio_context=%#x", <uintptr_t> self.audio_ctx) 1448 self.audio_ctx.sample_fmt = AV_SAMPLE_FMT_FLTP 1449 self.audio_ctx.time_base.den = 25 1450 self.audio_ctx.time_base.num = 1 1451 self.audio_ctx.bit_rate = 64000 1452 self.audio_ctx.sample_rate = 44100 1453 self.audio_ctx.channels = 2 1454 #if audio_codec.capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE: 1455 # pass 1456 #cdef AVDictionary *opts = NULL 1457 #av_dict_set(&opts, "strict", "experimental", 0) 1458 #r = avcodec_open2(audio_ctx, audio_codec, &opts) 1459 #av_dict_free(&opts) 1460 r = avcodec_open2(self.audio_ctx, self.audio_codec, NULL) 1461 if r!=0: 1462 raise Exception("could not open %s encoder context: %s" % (self.encoding, av_error_str(r))) 1463 if r!=0: 1464 raise Exception("could not open %s encoder context: %s" % ("aac", av_error_str(r))) 1465 r = avcodec_parameters_from_context(self.audio_stream.codecpar, self.audio_ctx) 1466 if r<0: 1467 raise Exception("could not copy audio context parameters %#x: %s" % (<uintptr_t> self.audio_stream.codecpar, av_error_str(r))) 1468 1469 1470 def clean(self): 1471 try: 1472 self.clean_encoder() 1473 except: 1474 log.error("cleanup failed", exc_info=True) 1475 self.video_codec = NULL 1476 self.audio_codec = NULL 1477 self.pix_fmt = 0 1478 self.src_format = "" 1479 self.av_frame = NULL #should be redundant 1480 self.frames = 0 1481 self.width = 0 1482 self.height = 0 1483 self.encoding = "" 1484 self.buffers = [] 1485 f = self.file 1486 if f: 1487 self.file = None 1488 f.close() 1489 1490 def clean_encoder(self): 1491 cdef int r 1492 log("%s.clean_encoder()", self) 1493 if self.av_frame: 1494 log("clean_encoder() freeing AVFrame: %#x", <uintptr_t> self.av_frame) 1495 av_frame_free(&self.av_frame) 1496 if self.muxer_ctx: 1497 if self.frames>0: 1498 log("clean_encoder() writing trailer to stream") 1499 av_write_trailer(self.muxer_ctx) 1500 if self.muxer_ctx.pb: 1501 av_free(self.muxer_ctx.pb) 1502 self.muxer_ctx.pb = NULL 1503 log("clean_encoder() freeing av format context %#x", <uintptr_t> self.muxer_ctx) 1504 avformat_free_context(self.muxer_ctx) 1505 self.muxer_ctx = NULL 1506 log("clean_encoder() freeing bitstream buffer %#x", <uintptr_t> self.buffer) 1507 if self.buffer: 1508 av_free(self.buffer) 1509 self.buffer = NULL 1510 log("clean_encoder() freeing AVCodecContext: %#x", <uintptr_t> self.video_ctx) 1511 if self.video_ctx: 1512 r = avcodec_close(self.video_ctx) 1513 if r!=0: 1514 log.error("Error: failed to close video encoder context %#x", <uintptr_t> self.video_ctx) 1515 log.error(" %s", av_error_str(r)) 1516 av_free(self.video_ctx) 1517 self.video_ctx = NULL 1518 if self.audio_ctx: 1519 r = avcodec_close(self.audio_ctx) 1520 if r!=0: 1521 log.error("Error: failed to close audio encoder context %#x", <uintptr_t> self.audio_ctx) 1522 log.error(" %s", av_error_str(r)) 1523 av_free(self.audio_ctx) 1524 self.audio_ctx = NULL 1525 if self.hw_device_ctx: 1526 av_buffer_unref(&self.hw_device_ctx) 1527 log("clean_encoder() done") 1528 1529 def __repr__(self): 1530 if self.is_closed(): 1531 return "enc_ffmpeg.Encoder(*closed*)" 1532 return "enc_ffmpeg.Encoder(%s)" % self.get_info() 1533 1534 def get_info(self) -> dict: 1535 info = { 1536 "version" : get_version(), 1537 "encoding" : self.encoding, 1538 "formats" : get_input_colorspaces(self.encoding), 1539 "type" : self.get_type(), 1540 "frames" : int(self.frames), 1541 "width" : self.width, 1542 "height" : self.height, 1543 } 1544 if self.muxer_format: 1545 info["muxer"] = self.muxer_format 1546 if self.video_codec: 1547 info["video-codec"] = self.video_codec.name[:] 1548 info["video-description"] = self.video_codec.long_name[:] 1549 if self.audio_codec: 1550 info["audio-codec"] = self.audio_codec.name[:] 1551 info["audio-description"] = self.audio_codec.long_name[:] 1552 if self.src_format: 1553 info["src_format"] = self.src_format 1554 if not self.is_closed(): 1555 info["encoder_width"] = self.video_ctx.width 1556 info["encoder_height"] = self.video_ctx.height 1557 else: 1558 info["closed"] = True 1559 return info 1560 1561 def is_closed(self): 1562 return self.video_ctx==NULL 1563 1564 def __dealloc__(self): 1565 self.clean() 1566 1567 def get_width(self): 1568 return self.width 1569 1570 def get_height(self): 1571 return self.height 1572 1573 def get_src_format(self): 1574 return self.src_format 1575 1576 def get_encoding(self): 1577 return self.encoding 1578 1579 def get_type(self): 1580 return "ffmpeg" 1581 1582 def get_delayed_frames(self): 1583 return 0 1584 1585 def log_av_error(self, image, err_no, options=None): 1586 msg = av_error_str(err_no) 1587 self.log_error(image, msg, options, "error %i" % err_no) 1588 1589 def log_error(self, image, err, options=None, error_type="error"): 1590 log.error("Error: ffmpeg %s encoding %s:", error_type, self.encoding) 1591 log.error(" '%s'", err) 1592 log.error(" on image %s", image) 1593 log.error(" frame number %i", self.frames) 1594 if options: 1595 log.error(" options=%s", options) 1596 log.error(" encoder state:") 1597 for k,v in self.get_info().items(): 1598 log.error(" %s = %s", k, v) 1599 1600 def compress_image(self, image=None, options=None): 1601 cdef int ret, i 1602 cdef AVFrame *frame 1603 cdef AVFrame *hw_frame = NULL 1604 cdef Py_buffer py_buf[4] 1605 assert self.video_ctx, "no codec context! (not initialized or already closed)" 1606 assert self.video_codec, "no video codec!" 1607 1608 for i in range(4): 1609 memset(&py_buf[i], 0, sizeof(Py_buffer)) 1610 1611 def release_buffers(): 1612 for i in range(4): 1613 if py_buf[i].buf: 1614 PyBuffer_Release(&py_buf[i]) 1615 1616 if image: 1617 assert image.get_pixel_format()==self.src_format, "invalid input format %s, expected %s" % (image.get_pixel_format, self.src_format) 1618 assert image.get_width()==self.width and image.get_height()==self.height 1619 1620 pixels = image.get_pixels() 1621 istrides = image.get_rowstride() 1622 assert len(pixels)==self.nplanes, "image pixels does not have %i planes! (found %s)" % (self.nplanes, len(pixels)) 1623 assert len(istrides)==self.nplanes, "image strides does not have %i values! (found %s)" % (self.nplanes, len(istrides)) 1624 #populate the avframe: 1625 ret = av_frame_make_writable(self.av_frame) 1626 if not ret!=0: 1627 raise Exception(av_error_str(ret)) 1628 for i in range(4): 1629 if i<self.nplanes: 1630 if PyObject_GetBuffer(pixels[i], &py_buf[i], PyBUF_ANY_CONTIGUOUS): 1631 raise Exception("failed to read pixel data from %s" % type(pixels[i])) 1632 #log("plane %s: %i bytes (%ix%i stride=%i)", ["Y", "U", "V"][i], buf_len, self.width, self.height, istrides[i]) 1633 self.av_frame.data[i] = <uint8_t *> py_buf[i].buf 1634 self.av_frame.linesize[i] = istrides[i] 1635 else: 1636 self.av_frame.data[i] = NULL 1637 self.av_frame.width = self.width 1638 self.av_frame.height = self.height 1639 self.av_frame.format = self.pix_fmt 1640 if self.encoding not in ("mpeg1", "mpeg2"): 1641 self.av_frame.pts = self.frames+1 1642 self.av_frame.coded_picture_number = self.frames+1 1643 self.av_frame.display_picture_number = self.frames+1 1644 #if self.frames==0: 1645 self.av_frame.pict_type = AV_PICTURE_TYPE_I 1646 #self.av_frame.key_frame = 1 1647 #else: 1648 # self.av_frame.pict_type = AV_PICTURE_TYPE_P 1649 #self.av_frame.quality = 1 1650 frame = self.av_frame 1651 else: 1652 assert options and options.get("flush"), "no image and no flush flag" 1653 frame = NULL 1654 1655 if self.vaapi and frame: 1656 #copy to hardware: 1657 hw_frame = av_frame_alloc() 1658 log("av_frame_alloc()=%#x", <uintptr_t> hw_frame) 1659 if hw_frame==NULL: 1660 release_buffers() 1661 log.error("Error: failed to allocate a hw frame") 1662 return None 1663 ret = av_hwframe_get_buffer(self.video_ctx.hw_frames_ctx, hw_frame, 0) 1664 log("av_frame_get_buffer(%#x, %#x, 0)=%i", <uintptr_t> self.video_ctx.hw_frames_ctx, <uintptr_t> hw_frame, ret) 1665 if ret<0 or hw_frame.hw_frames_ctx==NULL: 1666 release_buffers() 1667 log.error("Error: failed to allocate a hw buffer") 1668 log.error(" %s", av_error_str(ret)) 1669 return None 1670 ret = av_hwframe_transfer_data(hw_frame, frame, 0) 1671 log("av_hwframe_transfer_data(%#x, %#x, 0)=%i", <uintptr_t> hw_frame, <uintptr_t> frame, ret) 1672 if ret<0: 1673 release_buffers() 1674 log.error("Error: failed to transfer frame data to surface") 1675 log.error(" %s", av_error_str(ret)) 1676 return None 1677 frame = hw_frame 1678 log("compress_image%s avcodec_send_frame frame=%#x", (image, options), <uintptr_t> frame) 1679 with nogil: 1680 ret = avcodec_send_frame(self.video_ctx, frame) 1681 release_buffers() 1682 if ret!=0: 1683 self.log_av_error(image, ret, options) 1684 raise Exception("%i: %s" % (ret, av_error_str(ret))) 1685 1686 buf_len = 1024+self.width*self.height 1687 cdef AVPacket *avpkt = av_packet_alloc() 1688 avpkt.data = <uint8_t *> memalign(buf_len) 1689 avpkt.size = buf_len 1690 assert ret==0 1691 try: 1692 while ret==0: 1693 log("compress_image%s avcodec_receive_packet avpacket=%#x", (image, options), <uintptr_t> &avpkt) 1694 with nogil: 1695 ret = avcodec_receive_packet(self.video_ctx, avpkt) 1696 log("avcodec_receive_packet(..)=%i", ret) 1697 if ret==-errno.EAGAIN: 1698 log("ffmpeg avcodec_receive_packet EAGAIN") 1699 break 1700 if ret!=0: 1701 if not image: 1702 log("avcodec_receive_packet returned error '%s' for flush request", av_error_str(ret)) 1703 else: 1704 log("avcodec_receive_packet returned error '%s' for image %s, returning existing buffer", av_error_str(ret), image) 1705 break 1706 if ret<0: 1707 self.log_av_error(image, ret, options) 1708 raise Exception(av_error_str(ret)) 1709 if ret>0: 1710 self.log_av_error(image, ret, options, "no stream") 1711 raise Exception("no stream") 1712 log("avcodec_receive_packet returned %#x bytes of data, flags: %s", avpkt.size, flagscsv(PKT_FLAGS, avpkt.flags)) 1713 if avpkt.flags & AV_PKT_FLAG_CORRUPT: 1714 self.log_error(image, "packet", options, "av packet is corrupt") 1715 raise Exception("av packet is corrupt") 1716 1717 if self.muxer_format: 1718 #give the frame to the muxer: 1719 #(the muxer will append to self.buffers) 1720 avpkt.stream_index = self.video_stream.index 1721 r = av_write_frame(self.muxer_ctx, avpkt) 1722 log("av_write_frame packet returned %i", r) 1723 if ret<0: 1724 free(avpkt.data) 1725 self.log_av_error(image, ret, options) 1726 raise Exception(av_error_str(ret)) 1727 #flush muxer: 1728 while True: 1729 r = av_write_frame(self.muxer_ctx, NULL) 1730 log("av_write_frame flush returned %i", r) 1731 if r==1: 1732 break 1733 if ret<0: 1734 self.log_av_error(image, ret, options) 1735 raise Exception(av_error_str(ret)) 1736 else: 1737 #process frame data without a muxer: 1738 self.buffers.append(avpkt.data[:avpkt.size]) 1739 finally: 1740 free(avpkt.data) 1741 av_packet_free(&avpkt) 1742 if hw_frame: 1743 av_frame_free(&hw_frame) 1744 1745 #NV12 also uses YUV420P, 1746 #only with a different pixel layout 1747 #which is irrelevant to the client 1748 client_options = { 1749 "csc" : "YUV420P", 1750 } 1751 if self.frames==0 and self.profile: 1752 client_options["profile"] = self.profile 1753 client_options["level"] = "3.0" 1754 data = b"".join(self.buffers) 1755 if self.buffers and self.file: 1756 for x in self.buffers: 1757 self.file.write(x) 1758 self.file.flush() 1759 if self.encoding in ("mpeg1", "mpeg2"): 1760 #always one frame buffered 1761 client_options["delayed"] = 1 1762 if data: 1763 client_options["frame"] = int(self.frames) 1764 if self.frames==0: 1765 log("%s client options for first frame: %s", self.encoding, client_options) 1766 self.frames += 1 1767 log("compress_image(%s) %5i bytes (%i buffers) for %4s with client options: %s", image, len(data), len(self.buffers), self.encoding, client_options) 1768 self.buffers = [] 1769 return data, client_options 1770 1771 def flush(self, delayed): 1772 v = self.compress_image(options={"flush" : True}) 1773 #ffmpeg context cannot be re-used after a flush.. 1774 self.clean() 1775 return v 1776 1777 def write_packet(self, uintptr_t buf, int buf_size): 1778 log("write_packet(%#x, %#x)", <uintptr_t> buf, buf_size) 1779 cdef uint8_t *cbuf = <uint8_t*> buf 1780 buffer = cbuf[:buf_size] 1781 self.buffers.append(buffer) 1782 return buf_size 1783 1784 1785def selftest(full=False): 1786 global CODECS 1787 from xpra.codecs.codec_checks import testencoder 1788 from xpra.codecs.enc_ffmpeg import encoder 1789 with SilenceAVWarningsContext(): 1790 CODECS = testencoder(encoder, full) 1791