static GstFlowReturn theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet) { GstVideoEncoder *benc; GstFlowReturn ret; GstVideoCodecFrame *frame; benc = GST_VIDEO_ENCODER (enc); frame = gst_video_encoder_get_oldest_frame (benc); if (gst_video_encoder_allocate_output_frame (benc, frame, packet->bytes) != GST_FLOW_OK) { GST_WARNING_OBJECT (enc, "Could not allocate buffer"); gst_video_codec_frame_unref (frame); ret = GST_FLOW_ERROR; goto done; } gst_buffer_fill (frame->output_buffer, 0, packet->packet, packet->bytes); /* the second most significant bit of the first data byte is cleared * for keyframes */ if (packet->bytes > 0 && (packet->packet[0] & 0x40) == 0) { GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); } else { GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame); } enc->packetno++; ret = gst_video_encoder_finish_frame (benc, frame); done: return ret; }
static GstFlowReturn gst_av1_enc_process (GstAV1Enc * encoder) { aom_codec_iter_t iter = NULL; const aom_codec_cx_pkt_t *pkt; GstVideoCodecFrame *frame; GstVideoEncoder *video_encoder; GstFlowReturn ret = GST_FLOW_CUSTOM_SUCCESS; video_encoder = GST_VIDEO_ENCODER (encoder); while ((pkt = aom_codec_get_cx_data (&encoder->encoder, &iter)) != NULL) { if (pkt->kind == AOM_CODEC_STATS_PKT) { GST_WARNING_OBJECT (encoder, "Unhandled stats packet"); } else if (pkt->kind == AOM_CODEC_FPMB_STATS_PKT) { GST_WARNING_OBJECT (encoder, "Unhandled FPMB pkt"); } else if (pkt->kind == AOM_CODEC_PSNR_PKT) { GST_WARNING_OBJECT (encoder, "Unhandled PSNR packet"); } else if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) { frame = gst_video_encoder_get_oldest_frame (video_encoder); g_assert (frame != NULL); if ((pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0) { GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); } else { GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame); } frame->output_buffer = gst_buffer_new_wrapped (g_memdup (pkt->data.frame.buf, pkt->data.frame.sz), pkt->data.frame.sz); if ((pkt->data.frame.flags & AOM_FRAME_IS_DROPPABLE) != 0) GST_BUFFER_FLAG_SET (frame->output_buffer, GST_BUFFER_FLAG_DROPPABLE); if ((pkt->data.frame.flags & AOM_FRAME_IS_INVISIBLE) != 0) GST_BUFFER_FLAG_SET (frame->output_buffer, GST_BUFFER_FLAG_DECODE_ONLY); ret = gst_video_encoder_finish_frame (video_encoder, frame); if (ret != GST_FLOW_OK) break; } } return ret; }
static GstFlowReturn gst_openh264enc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) { GstOpenh264Enc *openh264enc = GST_OPENH264ENC (encoder); SSourcePicture *src_pic = NULL; GstVideoFrame video_frame; gboolean force_keyframe; gint ret; SFrameBSInfo frame_info; gfloat fps; GstMapInfo map; gint i, j; gsize buf_length = 0; if (frame) { src_pic = new SSourcePicture; if (src_pic == NULL) { if (frame) gst_video_codec_frame_unref (frame); return GST_FLOW_ERROR; } //fill default src_pic src_pic->iColorFormat = videoFormatI420; src_pic->uiTimeStamp = frame->pts / GST_MSECOND; } openh264enc->frame_count++; if (frame) { if (G_UNLIKELY (openh264enc->frame_count == 1)) { openh264enc->time_per_frame = (GST_SECOND / openh264enc->framerate); openh264enc->previous_timestamp = frame->pts; } else { openh264enc->time_per_frame = openh264enc->time_per_frame * 0.8 + (frame->pts - openh264enc->previous_timestamp) * 0.2; openh264enc->previous_timestamp = frame->pts; if (openh264enc->frame_count % 10 == 0) { fps = GST_SECOND / (gdouble) openh264enc->time_per_frame; openh264enc->encoder->SetOption (ENCODER_OPTION_FRAME_RATE, &fps); } } } if (frame) { gst_video_frame_map (&video_frame, &openh264enc->input_state->info, frame->input_buffer, GST_MAP_READ); src_pic->iPicWidth = GST_VIDEO_FRAME_WIDTH (&video_frame); src_pic->iPicHeight = GST_VIDEO_FRAME_HEIGHT (&video_frame); src_pic->iStride[0] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 0); src_pic->iStride[1] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 1); src_pic->iStride[2] = GST_VIDEO_FRAME_COMP_STRIDE (&video_frame, 2); src_pic->pData[0] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 0); src_pic->pData[1] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 1); src_pic->pData[2] = GST_VIDEO_FRAME_COMP_DATA (&video_frame, 2); force_keyframe = GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame); if (force_keyframe) { openh264enc->encoder->ForceIntraFrame (true); GST_DEBUG_OBJECT (openh264enc, "Got force key unit event, next frame coded as intra picture"); } } memset (&frame_info, 0, sizeof (SFrameBSInfo)); ret = openh264enc->encoder->EncodeFrame (src_pic, &frame_info); if (ret != cmResultSuccess) { if (frame) { gst_video_frame_unmap (&video_frame); gst_video_codec_frame_unref (frame); delete src_pic; GST_ELEMENT_ERROR (openh264enc, STREAM, ENCODE, ("Could not encode frame"), ("Openh264 returned %d", ret)); return GST_FLOW_ERROR; } else { return GST_FLOW_EOS; } } if (videoFrameTypeSkip == frame_info.eFrameType) { if (frame) { gst_video_frame_unmap (&video_frame); gst_video_encoder_finish_frame (encoder, frame); delete src_pic; } return GST_FLOW_OK; } if (frame) { gst_video_frame_unmap (&video_frame); gst_video_codec_frame_unref (frame); delete src_pic; src_pic = NULL; frame = NULL; } /* FIXME: openh264 has no way for us to get a connection * between the input and output frames, we just have to * guess based on the input */ frame = gst_video_encoder_get_oldest_frame (encoder); if (!frame) { GST_ELEMENT_ERROR (openh264enc, STREAM, ENCODE, ("Could not encode frame"), ("openh264enc returned %d", ret)); gst_video_codec_frame_unref (frame); return GST_FLOW_ERROR; } if (videoFrameTypeIDR == frame_info.eFrameType) { GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); } else { GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame); } for (i = 0; i < frame_info.iLayerNum; i++) { for (j = 0; j < frame_info.sLayerInfo[i].iNalCount; j++) { buf_length += frame_info.sLayerInfo[i].pNalLengthInByte[j]; } } frame->output_buffer = gst_video_encoder_allocate_output_buffer (encoder, buf_length); gst_buffer_map (frame->output_buffer, &map, GST_MAP_WRITE); buf_length = 0; for (i = 0; i < frame_info.iLayerNum; i++) { gsize layer_size = 0; for (j = 0; j < frame_info.sLayerInfo[i].iNalCount; j++) { layer_size += frame_info.sLayerInfo[i].pNalLengthInByte[j]; } memcpy (map.data + buf_length, frame_info.sLayerInfo[i].pBsBuf, layer_size); buf_length += layer_size; } gst_buffer_unmap (frame->output_buffer, &map); GST_LOG_OBJECT (openh264enc, "openh264 picture %scoded OK!", (ret != cmResultSuccess) ? "NOT " : ""); return gst_video_encoder_finish_frame (encoder, frame); }
static GstFlowReturn gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send) { GstVideoCodecFrame *frame; GstFlowReturn flow_ret = GST_FLOW_OK; GstBuffer *outbuf; gint ret_size; GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send); /* no need to empty codec if there is none */ if (!ffmpegenc->opened) goto done; while ((frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (ffmpegenc)))) { ffmpegenc_setup_working_buf (ffmpegenc); ret_size = avcodec_encode_video (ffmpegenc->context, ffmpegenc->working_buf, ffmpegenc->working_buf_size, NULL); if (ret_size < 0) { /* there should be something, notify and give up */ #ifndef GST_DISABLE_GST_DEBUG GstFFMpegVidEncClass *oclass = (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); GST_WARNING_OBJECT (ffmpegenc, "avenc_%s: failed to flush buffer", oclass->in_plugin->name); #endif /* GST_DISABLE_GST_DEBUG */ gst_video_codec_frame_unref (frame); break; } /* save stats info if there is some as well as a stats file */ if (ffmpegenc->file && ffmpegenc->context->stats_out) if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0) GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE, (("Could not write to file \"%s\"."), ffmpegenc->filename), GST_ERROR_SYSTEM); if (send) { if (gst_video_encoder_allocate_output_frame (GST_VIDEO_ENCODER (ffmpegenc), frame, ret_size) != GST_FLOW_OK) { #ifndef GST_DISABLE_GST_DEBUG GstFFMpegVidEncClass *oclass = (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); GST_WARNING_OBJECT (ffmpegenc, "avenc_%s: failed to allocate buffer", oclass->in_plugin->name); #endif /* GST_DISABLE_GST_DEBUG */ gst_video_codec_frame_unref (frame); break; } outbuf = frame->output_buffer; gst_buffer_fill (outbuf, 0, ffmpegenc->working_buf, ret_size); if (ffmpegenc->context->coded_frame->key_frame) GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); flow_ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame); } else { gst_video_codec_frame_unref (frame); } } done: return flow_ret; }
static GstFlowReturn gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) { GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder; GstBuffer *outbuf; gint ret_size = 0, c; GstVideoInfo *info = &ffmpegenc->input_state->info; GstVideoFrame vframe; if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) ffmpegenc->picture->pict_type = AV_PICTURE_TYPE_I; if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ)) { GST_ERROR_OBJECT (encoder, "Failed to map input buffer"); return GST_FLOW_ERROR; } /* Fill avpicture */ for (c = 0; c < AV_NUM_DATA_POINTERS; c++) { if (c < GST_VIDEO_INFO_N_COMPONENTS (info)) { ffmpegenc->picture->data[c] = GST_VIDEO_FRAME_PLANE_DATA (&vframe, c); ffmpegenc->picture->linesize[c] = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, c); } else { ffmpegenc->picture->data[c] = NULL; ffmpegenc->picture->linesize[c] = 0; } } ffmpegenc->picture->pts = gst_ffmpeg_time_gst_to_ff (frame->pts / ffmpegenc->context->ticks_per_frame, ffmpegenc->context->time_base); ffmpegenc_setup_working_buf (ffmpegenc); ret_size = avcodec_encode_video (ffmpegenc->context, ffmpegenc->working_buf, ffmpegenc->working_buf_size, ffmpegenc->picture); gst_video_frame_unmap (&vframe); if (ret_size < 0) goto encode_fail; /* Encoder needs more data */ if (!ret_size) return GST_FLOW_OK; /* save stats info if there is some as well as a stats file */ if (ffmpegenc->file && ffmpegenc->context->stats_out) if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0) GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE, (("Could not write to file \"%s\"."), ffmpegenc->filename), GST_ERROR_SYSTEM); gst_video_codec_frame_unref (frame); /* Get oldest frame */ frame = gst_video_encoder_get_oldest_frame (encoder); /* Allocate output buffer */ if (gst_video_encoder_allocate_output_frame (encoder, frame, ret_size) != GST_FLOW_OK) { gst_video_codec_frame_unref (frame); goto alloc_fail; } outbuf = frame->output_buffer; gst_buffer_fill (outbuf, 0, ffmpegenc->working_buf, ret_size); /* buggy codec may not set coded_frame */ if (ffmpegenc->context->coded_frame) { if (ffmpegenc->context->coded_frame->key_frame) GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); } else GST_WARNING_OBJECT (ffmpegenc, "codec did not provide keyframe info"); /* Reset frame type */ if (ffmpegenc->picture->pict_type) ffmpegenc->picture->pict_type = 0; return gst_video_encoder_finish_frame (encoder, frame); /* ERRORS */ encode_fail: { #ifndef GST_DISABLE_GST_DEBUG GstFFMpegVidEncClass *oclass = (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); GST_ERROR_OBJECT (ffmpegenc, "avenc_%s: failed to encode buffer", oclass->in_plugin->name); #endif /* GST_DISABLE_GST_DEBUG */ return GST_FLOW_OK; } alloc_fail: { #ifndef GST_DISABLE_GST_DEBUG GstFFMpegVidEncClass *oclass = (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); GST_ERROR_OBJECT (ffmpegenc, "avenc_%s: failed to allocate buffer", oclass->in_plugin->name); #endif /* GST_DISABLE_GST_DEBUG */ return GST_FLOW_ERROR; } }
static GstFlowReturn gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send) { GstVideoCodecFrame *frame; GstFlowReturn flow_ret = GST_FLOW_OK; GstBuffer *outbuf; gint ret; AVPacket *pkt; int have_data = 0; GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send); /* no need to empty codec if there is none */ if (!ffmpegenc->opened) goto done; while ((frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (ffmpegenc)))) { pkt = g_slice_new0 (AVPacket); have_data = 0; ret = avcodec_encode_video2 (ffmpegenc->context, pkt, NULL, &have_data); if (ret < 0) { /* there should be something, notify and give up */ #ifndef GST_DISABLE_GST_DEBUG GstFFMpegVidEncClass *oclass = (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); GST_WARNING_OBJECT (ffmpegenc, "avenc_%s: failed to flush buffer", oclass->in_plugin->name); #endif /* GST_DISABLE_GST_DEBUG */ g_slice_free (AVPacket, pkt); gst_video_codec_frame_unref (frame); break; } /* save stats info if there is some as well as a stats file */ if (ffmpegenc->file && ffmpegenc->context->stats_out) if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0) GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE, (("Could not write to file \"%s\"."), ffmpegenc->filename), GST_ERROR_SYSTEM); if (send && have_data) { outbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data, pkt->size, 0, pkt->size, pkt, gst_ffmpegvidenc_free_avpacket); frame->output_buffer = outbuf; if (pkt->flags & AV_PKT_FLAG_KEY) GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); else GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame); flow_ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame); } else { /* no frame attached, so will be skipped and removed from frame list */ gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame); } } done: return flow_ret; }
static GstFlowReturn gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) { GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder; GstBuffer *outbuf; gint ret = 0, c; GstVideoInfo *info = &ffmpegenc->input_state->info; AVPacket *pkt; int have_data = 0; BufferInfo *buffer_info; if (ffmpegenc->interlaced) { ffmpegenc->picture->interlaced_frame = TRUE; /* if this is not the case, a filter element should be used to swap fields */ ffmpegenc->picture->top_field_first = GST_BUFFER_FLAG_IS_SET (frame->input_buffer, GST_VIDEO_BUFFER_FLAG_TFF); } if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) ffmpegenc->picture->pict_type = AV_PICTURE_TYPE_I; buffer_info = g_slice_new0 (BufferInfo); buffer_info->buffer = gst_buffer_ref (frame->input_buffer); if (!gst_video_frame_map (&buffer_info->vframe, info, frame->input_buffer, GST_MAP_READ)) { GST_ERROR_OBJECT (encoder, "Failed to map input buffer"); gst_buffer_unref (buffer_info->buffer); g_slice_free (BufferInfo, buffer_info); gst_video_codec_frame_unref (frame); return GST_FLOW_ERROR; } /* Fill avpicture */ ffmpegenc->picture->buf[0] = av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0); for (c = 0; c < AV_NUM_DATA_POINTERS; c++) { if (c < GST_VIDEO_INFO_N_COMPONENTS (info)) { ffmpegenc->picture->data[c] = GST_VIDEO_FRAME_PLANE_DATA (&buffer_info->vframe, c); ffmpegenc->picture->linesize[c] = GST_VIDEO_FRAME_COMP_STRIDE (&buffer_info->vframe, c); } else { ffmpegenc->picture->data[c] = NULL; ffmpegenc->picture->linesize[c] = 0; } } ffmpegenc->picture->format = ffmpegenc->context->pix_fmt; ffmpegenc->picture->width = GST_VIDEO_FRAME_WIDTH (&buffer_info->vframe); ffmpegenc->picture->height = GST_VIDEO_FRAME_HEIGHT (&buffer_info->vframe); ffmpegenc->picture->pts = gst_ffmpeg_time_gst_to_ff (frame->pts / ffmpegenc->context->ticks_per_frame, ffmpegenc->context->time_base); have_data = 0; pkt = g_slice_new0 (AVPacket); ret = avcodec_encode_video2 (ffmpegenc->context, pkt, ffmpegenc->picture, &have_data); av_frame_unref (ffmpegenc->picture); if (ret < 0 || !have_data) g_slice_free (AVPacket, pkt); if (ret < 0) goto encode_fail; /* Encoder needs more data */ if (!have_data) { gst_video_codec_frame_unref (frame); return GST_FLOW_OK; } /* save stats info if there is some as well as a stats file */ if (ffmpegenc->file && ffmpegenc->context->stats_out) if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0) GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE, (("Could not write to file \"%s\"."), ffmpegenc->filename), GST_ERROR_SYSTEM); gst_video_codec_frame_unref (frame); /* Get oldest frame */ frame = gst_video_encoder_get_oldest_frame (encoder); outbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data, pkt->size, 0, pkt->size, pkt, gst_ffmpegvidenc_free_avpacket); frame->output_buffer = outbuf; if (pkt->flags & AV_PKT_FLAG_KEY) GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); else GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame); return gst_video_encoder_finish_frame (encoder, frame); /* ERRORS */ encode_fail: { #ifndef GST_DISABLE_GST_DEBUG GstFFMpegVidEncClass *oclass = (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); GST_ERROR_OBJECT (ffmpegenc, "avenc_%s: failed to encode buffer", oclass->in_plugin->name); #endif /* GST_DISABLE_GST_DEBUG */ /* avoid frame (and ts etc) piling up */ return gst_video_encoder_finish_frame (encoder, frame); } }