1/* 2 * GStreamer 3 * Copyright (C) 2013 Fluendo S.L. <support@fluendo.com> 4 * Authors: Andoni Morales Alastruey <amorales@fluendo.com> 5 * Copyright (C) 2014 Collabora Ltd. 6 * Authors: Matthieu Bouron <matthieu.bouron@collabora.com> 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public 19 * License along with this library; if not, write to the 20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 21 * Boston, MA 02111-1307, USA. 22 */ 23 24/** 25 * SECTION:element-avfassetsrc 26 * 27 * Read and decode samples from AVFoundation assets using the AVFAssetReader API 28 * 29 * ## Example launch line 30 * 31 * |[ 32 * gst-launch-1.0 -v -m avfassetsrc uri="file://movie.mp4" ! autovideosink 33 * ]| 34 */ 35 36#ifdef HAVE_CONFIG_H 37# include <config.h> 38#endif 39 40#include "avfassetsrc.h" 41#include "coremediabuffer.h" 42 43GST_DEBUG_CATEGORY_STATIC (gst_avf_asset_src_debug); 44#define GST_CAT_DEFAULT gst_avf_asset_src_debug 45 46#define CMTIME_TO_GST_TIME(x) \ 47 (x.value == 0 ? 0 : (guint64)(x.value * GST_SECOND / x.timescale)); 48#define GST_AVF_ASSET_SRC_LOCK(x) (g_mutex_lock (&x->lock)); 49#define GST_AVF_ASSET_SRC_UNLOCK(x) (g_mutex_unlock (&x->lock)); 50#define MEDIA_TYPE_TO_STR(x) \ 51 (x == GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO ? "audio" : "video") 52#define AVF_ASSET_READER_HAS_AUDIO(x) \ 53 ([GST_AVF_ASSET_SRC_READER(self) hasMediaType:GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO]) 54#define AVF_ASSET_READER_HAS_VIDEO(x) \ 55 ([GST_AVF_ASSET_SRC_READER(self) hasMediaType:GST_AVF_ASSET_READER_MEDIA_TYPE_VIDEO]) 56 57enum 58{ 59 PROP_0, 60 PROP_URI 61}; 62 63static GstStaticPadTemplate audio_factory = GST_STATIC_PAD_TEMPLATE ("audio", 64 GST_PAD_SRC, 65 GST_PAD_SOMETIMES, 66 GST_STATIC_CAPS ("audio/x-raw, " 67 "format = (string) F32LE, " 68 "rate = " GST_AUDIO_RATE_RANGE ", " 69 "channels = (int) [1, 2], " 70 "layout = (string) interleaved" 71 ) 72); 73 74static GstStaticPadTemplate video_factory = GST_STATIC_PAD_TEMPLATE ("video", 75 GST_PAD_SRC, 76 GST_PAD_SOMETIMES, 77 GST_STATIC_CAPS ("video/x-raw, " 78 "format = (string) NV12, " 79 "framerate = " GST_VIDEO_FPS_RANGE ", " 80 "width = " GST_VIDEO_SIZE_RANGE ", " 81 "height = " GST_VIDEO_SIZE_RANGE 82 ) 83); 84 85static void gst_avf_asset_src_set_property (GObject * object, guint prop_id, 86 const GValue * value, GParamSpec * pspec); 87static void gst_avf_asset_src_get_property (GObject * object, guint prop_id, 88 GValue * value, GParamSpec * pspec); 89static void gst_avf_asset_src_dispose (GObject *object); 90 91static GstStateChangeReturn gst_avf_asset_src_change_state (GstElement * element, 92 GstStateChange transition); 93 94static gboolean gst_avf_asset_src_query (GstPad *pad, GstObject * parent, GstQuery *query); 95static gboolean gst_avf_asset_src_event (GstPad *pad, GstObject * parent, GstEvent *event); 96static gboolean gst_avf_asset_src_send_event (GstAVFAssetSrc *self, 97 GstEvent *event); 98 99static void gst_avf_asset_src_read_audio (GstAVFAssetSrc *self); 100static void gst_avf_asset_src_read_video (GstAVFAssetSrc *self); 101static void gst_avf_asset_src_start (GstAVFAssetSrc *self); 102static void gst_avf_asset_src_stop (GstAVFAssetSrc *self); 103static gboolean gst_avf_asset_src_start_reading (GstAVFAssetSrc *self); 104static void gst_avf_asset_src_stop_reading (GstAVFAssetSrc *self); 105static void gst_avf_asset_src_stop_all (GstAVFAssetSrc *self); 106static void gst_avf_asset_src_uri_handler_init (gpointer g_iface, 107 gpointer iface_data); 108 109static void 110_do_init (GType avf_assetsrc_type) 111{ 112 static const GInterfaceInfo urihandler_info = { 113 gst_avf_asset_src_uri_handler_init, 114 NULL, 115 NULL 116 }; 117 118 g_type_add_interface_static (avf_assetsrc_type, GST_TYPE_URI_HANDLER, 119 &urihandler_info); 120 GST_DEBUG_CATEGORY_INIT (gst_avf_asset_src_debug, "avfassetsrc", 121 0, "avfassetsrc element"); 122} 123 124G_DEFINE_TYPE_WITH_CODE (GstAVFAssetSrc, gst_avf_asset_src, GST_TYPE_ELEMENT, 125 _do_init (g_define_type_id)); 126 127 128/* GObject vmethod implementations */ 129 130static void 131gst_avf_asset_src_class_init (GstAVFAssetSrcClass * klass) 132{ 133 GObjectClass *gobject_class; 134 GstElementClass *gstelement_class; 135 136 gobject_class = (GObjectClass *) klass; 137 gstelement_class = (GstElementClass *) klass; 138 139 gst_element_class_set_static_metadata (gstelement_class, 140 "Source and decoder for AVFoundation assets", 141 "Source/Codec", 142 "Read and decode samples from AVFoundation assets using the AVFAssetReader API", 143 "Andoni Morales Alastruey amorales@fluendo.com"); 144 145 gst_element_class_add_static_pad_template (gstelement_class, &audio_factory); 146 gst_element_class_add_static_pad_template (gstelement_class, &video_factory); 147 148 gobject_class->set_property = gst_avf_asset_src_set_property; 149 gobject_class->get_property = gst_avf_asset_src_get_property; 150 gobject_class->dispose = gst_avf_asset_src_dispose; 151 152 g_object_class_install_property (gobject_class, PROP_URI, 153 g_param_spec_string ("uri", "Asset URI", 154 "URI of the asset to read", NULL, 155 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | 156 GST_PARAM_MUTABLE_READY)); 157 158 gstelement_class->change_state = gst_avf_asset_src_change_state; 159 160} 161 162static void 163gst_avf_asset_src_init (GstAVFAssetSrc * self) 164{ 165 self->selected_audio_track = 0; 166 self->selected_video_track = 0; 167 self->last_audio_pad_ret = GST_FLOW_OK; 168 self->last_video_pad_ret = GST_FLOW_OK; 169 g_mutex_init (&self->lock); 170} 171 172static void 173gst_avf_asset_src_dispose (GObject *object) 174{ 175 GstAVFAssetSrc *self = GST_AVF_ASSET_SRC (object); 176 177 if (self->uri != NULL) { 178 g_free (self->uri); 179 self->uri = NULL; 180 } 181 182 if (self->seek_event) { 183 gst_event_unref (self->seek_event); 184 self->seek_event = NULL; 185 } 186} 187 188static void 189gst_avf_asset_src_set_property (GObject * object, guint prop_id, 190 const GValue * value, GParamSpec * pspec) 191{ 192 GstAVFAssetSrc *self = GST_AVF_ASSET_SRC (object); 193 194 switch (prop_id) { 195 case PROP_URI: 196 g_free (self->uri); 197 self->uri = g_value_dup_string (value); 198 break; 199 default: 200 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 201 break; 202 } 203} 204 205static void 206gst_avf_asset_src_get_property (GObject * object, guint prop_id, 207 GValue * value, GParamSpec * pspec) 208{ 209 GstAVFAssetSrc *self = GST_AVF_ASSET_SRC (object); 210 211 switch (prop_id) { 212 case PROP_URI: 213 g_value_set_string (value, self->uri); 214 break; 215 default: 216 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 217 break; 218 } 219} 220 221static GstStateChangeReturn 222gst_avf_asset_src_change_state (GstElement * element, GstStateChange transition) 223{ 224 GstAVFAssetSrc *self = GST_AVF_ASSET_SRC (element); 225 GstStateChangeReturn ret; 226 GError *error; 227 228 GST_DEBUG ("%s => %s", 229 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)), 230 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); 231 232 switch (transition) { 233 case GST_STATE_CHANGE_NULL_TO_READY: { 234 self->state = GST_AVF_ASSET_SRC_STATE_STOPPED; 235 if (!self->uri) { 236 GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, 237 ("\"uri\" property not set"), (NULL)); 238 gst_avf_asset_src_stop_all (self); 239 return GST_STATE_CHANGE_FAILURE; 240 } 241 self->reader = (__bridge_retained gpointer)([[GstAVFAssetReader alloc] initWithURI:self->uri:&error]); 242 if (error) { 243 GST_ELEMENT_ERROR (element, RESOURCE, FAILED, ("AVFAssetReader error"), 244 ("%s", error->message)); 245 g_error_free (error); 246 gst_avf_asset_src_stop_all (self); 247 return GST_STATE_CHANGE_FAILURE; 248 } 249 break; 250 } 251 case GST_STATE_CHANGE_READY_TO_PAUSED: 252 gst_avf_asset_src_start (self); 253 gst_avf_asset_src_start_reading (self); 254 break; 255 case GST_STATE_CHANGE_PAUSED_TO_PLAYING: 256 break; 257 default: 258 break; 259 } 260 261 ret = GST_ELEMENT_CLASS (gst_avf_asset_src_parent_class)->change_state (element, transition); 262 263 switch (transition) { 264 case GST_STATE_CHANGE_PLAYING_TO_PAUSED: 265 break; 266 case GST_STATE_CHANGE_PAUSED_TO_READY: 267 gst_avf_asset_src_stop_reading (self); 268 gst_avf_asset_src_stop (self); 269 break; 270 case GST_STATE_CHANGE_READY_TO_NULL: 271 CFBridgingRelease(self->reader); 272 break; 273 default: 274 break; 275 } 276 return ret; 277} 278 279static GstCaps * 280gst_avf_asset_src_get_caps(GstAVFAssetSrc * self, GstPad * pad, GstCaps * filter) 281{ 282 GstCaps * caps; 283 284 caps = gst_pad_get_current_caps (pad); 285 if (!caps) { 286 caps = gst_pad_get_pad_template_caps (pad); 287 } 288 289 if (filter) { 290 GstCaps *intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); 291 gst_caps_unref (caps); 292 caps = intersection; 293 } 294 295 return caps; 296} 297 298static gboolean 299gst_avf_asset_src_query (GstPad *pad, GstObject * parent, GstQuery *query) 300{ 301 gboolean ret = FALSE; 302 GstCaps *caps; 303 GstAVFAssetSrc *self = GST_AVF_ASSET_SRC (parent); 304 305 switch (GST_QUERY_TYPE (query)) { 306 case GST_QUERY_URI: 307 gst_query_set_uri (query, self->uri); 308 ret = TRUE; 309 break; 310 case GST_QUERY_DURATION: 311 gst_query_set_duration (query, GST_FORMAT_TIME, GST_AVF_ASSET_SRC_READER(self).duration); 312 ret = TRUE; 313 break; 314 case GST_QUERY_POSITION: 315 gst_query_set_position (query, GST_FORMAT_TIME, GST_AVF_ASSET_SRC_READER(self).position); 316 ret = TRUE; 317 break; 318 case GST_QUERY_SEEKING: { 319 GstFormat fmt; 320 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); 321 if (fmt == GST_FORMAT_TIME) { 322 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, GST_AVF_ASSET_SRC_READER(self).duration); 323 ret = TRUE; 324 } 325 break; 326 } 327 case GST_QUERY_CAPS: { 328 GstCaps *filter = NULL; 329 gst_query_parse_caps (query, &filter); 330 caps = gst_avf_asset_src_get_caps (self, pad, filter); 331 gst_query_set_caps_result (query, caps); 332 ret = TRUE; 333 break; 334 } 335 default: 336 ret = FALSE; 337 break; 338 } 339 340 return ret; 341} 342 343static gboolean 344gst_avf_asset_src_event (GstPad * pad, GstObject * parent, GstEvent * event) 345{ 346 GstAVFAssetSrc *self; 347 gboolean res = TRUE; 348 GError *error = NULL; 349 350 self = GST_AVF_ASSET_SRC (gst_pad_get_parent_element (pad)); 351 352 switch (GST_EVENT_TYPE (event)) { 353 case GST_EVENT_SEEK: { 354 GstFormat format; 355 GstSeekFlags flags; 356 gdouble rate; 357 GstSeekType start_type, stop_type; 358 gint64 start, stop; 359 GstSegment segment; 360 361 GST_DEBUG ("Processing SEEK event"); 362 363 GST_AVF_ASSET_SRC_LOCK (self); 364 if (self->seek_event && gst_event_get_seqnum (event) == 365 gst_event_get_seqnum (self->seek_event)) { 366 GST_AVF_ASSET_SRC_UNLOCK (self); 367 break; 368 } 369 self->seek_event = gst_event_ref (event); 370 GST_AVF_ASSET_SRC_UNLOCK (self); 371 372 /* pause tasks before re-acquiring the object's lock */ 373 gst_avf_asset_src_stop_reading (self); 374 GST_AVF_ASSET_SRC_LOCK (self); 375 376 gst_event_parse_seek (event, &rate, &format, &flags, &start_type, 377 &start, &stop_type, &stop); 378 379 if (rate < 0) { 380 GST_WARNING ("Negative rates are not supported yet"); 381 GST_AVF_ASSET_SRC_UNLOCK (self); 382 res = FALSE; 383 break; 384 } 385 386 if (format != GST_FORMAT_TIME || start_type == GST_SEEK_TYPE_NONE) { 387 GST_AVF_ASSET_SRC_UNLOCK(self); 388 gst_avf_asset_src_start_reading (self); 389 res = FALSE; 390 break; 391 } 392 if (stop_type == GST_SEEK_TYPE_NONE) { 393 stop = GST_CLOCK_TIME_NONE; 394 } 395 gst_avf_asset_src_send_event (self, gst_event_new_flush_start ()); 396 [GST_AVF_ASSET_SRC_READER(self) seekTo: start: stop: &error]; 397 398 gst_segment_init (&segment, GST_FORMAT_TIME); 399 segment.rate = rate; 400 segment.start = start; 401 segment.stop = stop; 402 segment.position = start; 403 404 gst_avf_asset_src_send_event (self, gst_event_new_flush_stop (TRUE)); 405 gst_avf_asset_src_send_event (self, gst_event_new_segment (&segment)); 406 407 if (error != NULL) { 408 GST_ELEMENT_ERROR (self, RESOURCE, SEEK, 409 ("AVFAssetReader seek failed"), ("%s", error->message)); 410 g_error_free(error); 411 res = FALSE; 412 } 413 GST_AVF_ASSET_SRC_UNLOCK (self); 414 gst_event_unref (event); 415 416 /* start tasks after releasing the object's lock */ 417 gst_avf_asset_src_start_reading (self); 418 break; 419 } 420 default: 421 res = gst_pad_event_default (pad, parent, event); 422 break; 423 } 424 425 gst_object_unref (self); 426 return res; 427} 428 429static GstFlowReturn 430gst_avf_asset_src_send_start_stream (GstAVFAssetSrc * self, GstPad * pad) 431{ 432 GstEvent *event; 433 gchar *stream_id; 434 GstFlowReturn ret; 435 436 stream_id = gst_pad_create_stream_id (pad, GST_ELEMENT_CAST (self), NULL); 437 GST_DEBUG_OBJECT (self, "Pushing STREAM START"); 438 event = gst_event_new_stream_start (stream_id); 439 gst_event_set_group_id (event, gst_util_group_id_next ()); 440 441 ret = gst_pad_push_event (pad, event); 442 g_free (stream_id); 443 444 return ret; 445} 446 447static GstFlowReturn 448gst_avf_asset_src_combine_flows (GstAVFAssetSrc * self, GstAVFAssetReaderMediaType type, 449 GstFlowReturn ret) 450{ 451 gboolean has_other_pad; 452 GstFlowReturn last_other_pad_ret; 453 454 GST_AVF_ASSET_SRC_LOCK (self); 455 if (type == GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO) { 456 self->last_audio_pad_ret = ret; 457 has_other_pad = AVF_ASSET_READER_HAS_VIDEO (ret); 458 last_other_pad_ret = self->last_video_pad_ret; 459 } else if (type == GST_AVF_ASSET_READER_MEDIA_TYPE_VIDEO) { 460 self->last_video_pad_ret = ret; 461 has_other_pad = AVF_ASSET_READER_HAS_AUDIO (ret); 462 last_other_pad_ret = self->last_audio_pad_ret; 463 } else { 464 GST_ERROR ("Unsupported media type"); 465 ret = GST_FLOW_ERROR; 466 goto exit; 467 } 468 469 if (!has_other_pad || ret != GST_FLOW_NOT_LINKED) 470 goto exit; 471 472 ret = last_other_pad_ret; 473 474exit: 475 GST_AVF_ASSET_SRC_UNLOCK (self); 476 return ret; 477} 478 479static void 480gst_avf_asset_src_read_data (GstAVFAssetSrc *self, GstPad *pad, 481 GstAVFAssetReaderMediaType type) 482{ 483 GstBuffer *buf; 484 GstFlowReturn ret, combined_ret; 485 GError *error; 486 487 488 GST_AVF_ASSET_SRC_LOCK (self); 489 if (self->state != GST_AVF_ASSET_SRC_STATE_READING) { 490 GST_AVF_ASSET_SRC_UNLOCK (self); 491 return; 492 } 493 494 buf = [GST_AVF_ASSET_SRC_READER(self) nextBuffer:type:&error]; 495 GST_AVF_ASSET_SRC_UNLOCK (self); 496 497 if (buf == NULL) { 498 if (error != NULL) { 499 GST_ELEMENT_ERROR (self, RESOURCE, READ, ("Error reading next buffer"), 500 ("%s", error->message)); 501 g_error_free (error); 502 503 gst_avf_asset_src_combine_flows (self, type, GST_FLOW_ERROR); 504 gst_pad_pause_task (pad); 505 return; 506 } 507 508 gst_pad_push_event (pad, gst_event_new_eos ()); 509 gst_avf_asset_src_combine_flows (self, type, GST_FLOW_EOS); 510 gst_pad_pause_task (pad); 511 return; 512 } 513 514 ret = gst_pad_push (pad, buf); 515 combined_ret = gst_avf_asset_src_combine_flows (self, type, ret); 516 517 if (ret != GST_FLOW_OK) { 518 GST_WARNING ("Error pushing %s buffer on pad %" GST_PTR_FORMAT 519 ", reason %s", MEDIA_TYPE_TO_STR (type), pad, gst_flow_get_name (ret)); 520 521 if (ret == GST_FLOW_EOS) { 522 gst_pad_push_event (pad, gst_event_new_eos ()); 523 } 524 525 if (combined_ret != GST_FLOW_OK) { 526 GST_ELEMENT_FLOW_ERROR (self, ret); 527 } 528 529 gst_pad_pause_task (pad); 530 } 531 532} 533 534static void 535gst_avf_asset_src_read_audio (GstAVFAssetSrc *self) 536{ 537 gst_avf_asset_src_read_data (self, self->audiopad, 538 GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO); 539} 540 541static void 542gst_avf_asset_src_read_video (GstAVFAssetSrc *self) 543{ 544 gst_avf_asset_src_read_data (self, self->videopad, 545 GST_AVF_ASSET_READER_MEDIA_TYPE_VIDEO); 546} 547 548static gboolean 549gst_avf_asset_src_start_reader (GstAVFAssetSrc * self) 550{ 551 GError *error = NULL; 552 gboolean ret = TRUE; 553 554 555 [GST_AVF_ASSET_SRC_READER(self) start: &error]; 556 if (error != NULL) { 557 GST_ELEMENT_ERROR (self, RESOURCE, FAILED, 558 ("AVFAssetReader could not start reading"), ("%s", error->message)); 559 g_error_free (error); 560 ret = FALSE; 561 goto exit; 562 } 563 564exit: 565 return ret; 566} 567 568static gboolean 569gst_avf_asset_src_send_event (GstAVFAssetSrc *self, GstEvent *event) 570{ 571 gboolean ret = TRUE; 572 573 574 if (AVF_ASSET_READER_HAS_VIDEO (self)) { 575 ret |= gst_pad_push_event (self->videopad, gst_event_ref (event)); 576 } 577 if (AVF_ASSET_READER_HAS_AUDIO (self)) { 578 ret |= gst_pad_push_event (self->audiopad, gst_event_ref (event)); 579 } 580 581 gst_event_unref (event); 582 return ret; 583} 584 585static void 586gst_avf_asset_src_start (GstAVFAssetSrc *self) 587{ 588 GstSegment segment; 589 590 if (self->state == GST_AVF_ASSET_SRC_STATE_STARTED) { 591 return; 592 } 593 594 GST_DEBUG_OBJECT (self, "Creating pads and starting reader"); 595 596 gst_segment_init (&segment, GST_FORMAT_TIME); 597 segment.duration = GST_AVF_ASSET_SRC_READER(self).duration; 598 599 /* We call AVFAssetReader's startReading when the pads are linked 600 * and no outputs can be added afterwards, so the tracks must be 601 * selected before adding any of the new pads */ 602 if (AVF_ASSET_READER_HAS_AUDIO (self)) { 603 [GST_AVF_ASSET_SRC_READER(self) selectTrack: GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO: 604 self->selected_audio_track]; 605 } 606 if (AVF_ASSET_READER_HAS_VIDEO (self)) { 607 [GST_AVF_ASSET_SRC_READER(self) selectTrack: GST_AVF_ASSET_READER_MEDIA_TYPE_VIDEO: 608 self->selected_video_track]; 609 } 610 611 if (AVF_ASSET_READER_HAS_AUDIO (self)) { 612 self->audiopad = gst_pad_new_from_static_template (&audio_factory, "audio"); 613 gst_pad_set_query_function (self->audiopad, 614 gst_avf_asset_src_query); 615 gst_pad_set_event_function(self->audiopad, 616 gst_avf_asset_src_event); 617 gst_pad_use_fixed_caps (self->audiopad); 618 gst_pad_set_active (self->audiopad, TRUE); 619 gst_avf_asset_src_send_start_stream (self, self->audiopad); 620 gst_pad_set_caps (self->audiopad, 621 [GST_AVF_ASSET_SRC_READER(self) getCaps: GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO]); 622 gst_pad_push_event (self->audiopad, gst_event_new_caps ( 623 [GST_AVF_ASSET_SRC_READER(self) getCaps: GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO])); 624 gst_pad_push_event (self->audiopad, gst_event_new_segment (&segment)); 625 gst_element_add_pad (GST_ELEMENT (self), self->audiopad); 626 } 627 if (AVF_ASSET_READER_HAS_VIDEO (self)) { 628 self->videopad = gst_pad_new_from_static_template (&video_factory, "video"); 629 gst_pad_set_query_function (self->videopad, 630 gst_avf_asset_src_query); 631 gst_pad_set_event_function(self->videopad, 632 gst_avf_asset_src_event); 633 gst_pad_use_fixed_caps (self->videopad); 634 gst_pad_set_active (self->videopad, TRUE); 635 gst_avf_asset_src_send_start_stream (self, self->videopad); 636 gst_pad_set_caps (self->videopad, 637 [GST_AVF_ASSET_SRC_READER(self) getCaps: GST_AVF_ASSET_READER_MEDIA_TYPE_VIDEO]); 638 gst_pad_push_event (self->videopad, gst_event_new_caps ( 639 [GST_AVF_ASSET_SRC_READER(self) getCaps: GST_AVF_ASSET_READER_MEDIA_TYPE_VIDEO])); 640 gst_pad_push_event (self->videopad, gst_event_new_segment (&segment)); 641 gst_element_add_pad (GST_ELEMENT (self), self->videopad); 642 } 643 gst_element_no_more_pads (GST_ELEMENT (self)); 644 645 self->state = GST_AVF_ASSET_SRC_STATE_STARTED; 646} 647 648static void 649gst_avf_asset_src_stop (GstAVFAssetSrc *self) 650{ 651 gboolean has_audio, has_video; 652 653 if (self->state == GST_AVF_ASSET_SRC_STATE_STOPPED) { 654 return; 655 } 656 657 GST_DEBUG ("Stopping tasks and removing pads"); 658 659 has_audio = AVF_ASSET_READER_HAS_AUDIO (self); 660 has_video = AVF_ASSET_READER_HAS_VIDEO (self); 661 [GST_AVF_ASSET_SRC_READER(self) stop]; 662 663 if (has_audio) { 664 gst_pad_stop_task (self->audiopad); 665 gst_element_remove_pad (GST_ELEMENT (self), self->audiopad); 666 } 667 if (has_video) { 668 gst_pad_stop_task (self->videopad); 669 gst_element_remove_pad (GST_ELEMENT (self), self->videopad); 670 } 671 672 self->state = GST_AVF_ASSET_SRC_STATE_STOPPED; 673} 674 675static gboolean 676gst_avf_asset_src_start_reading (GstAVFAssetSrc *self) 677{ 678 gboolean ret = TRUE; 679 680 if (self->state != GST_AVF_ASSET_SRC_STATE_STARTED) { 681 goto exit; 682 } 683 684 GST_DEBUG_OBJECT (self, "Start reading"); 685 686 if ((ret = gst_avf_asset_src_start_reader (self)) != TRUE) { 687 goto exit; 688 } 689 690 if (AVF_ASSET_READER_HAS_AUDIO (self)) { 691 ret = gst_pad_start_task (self->audiopad, (GstTaskFunction)gst_avf_asset_src_read_audio, self, NULL); 692 if (!ret) { 693 GST_ERROR ("Failed to start audio task"); 694 goto exit; 695 } 696 } 697 698 if (AVF_ASSET_READER_HAS_VIDEO (self)) { 699 ret = gst_pad_start_task (self->videopad, (GstTaskFunction)gst_avf_asset_src_read_video, self, NULL); 700 if (!ret) { 701 GST_ERROR ("Failed to start video task"); 702 goto exit; 703 } 704 } 705 706 self->state = GST_AVF_ASSET_SRC_STATE_READING; 707 708exit: 709 return ret; 710} 711 712static void 713gst_avf_asset_src_stop_reading (GstAVFAssetSrc * self) 714{ 715 if (self->state != GST_AVF_ASSET_SRC_STATE_READING) { 716 return; 717 } 718 719 GST_DEBUG_OBJECT (self, "Stop reading"); 720 721 if (AVF_ASSET_READER_HAS_AUDIO (self)) { 722 gst_pad_pause_task (self->audiopad); 723 } 724 if (AVF_ASSET_READER_HAS_VIDEO (self)) { 725 gst_pad_pause_task (self->videopad); 726 } 727 728 self->state = GST_AVF_ASSET_SRC_STATE_STARTED; 729} 730 731static void 732gst_avf_asset_src_stop_all (GstAVFAssetSrc *self) 733{ 734 GST_AVF_ASSET_SRC_LOCK (self); 735 gst_avf_asset_src_stop_reading (self); 736 gst_avf_asset_src_stop (self); 737 GST_AVF_ASSET_SRC_UNLOCK (self); 738} 739 740static GQuark 741gst_avf_asset_src_error_quark (void) 742{ 743 static GQuark q; /* 0 */ 744 745 if (G_UNLIKELY (q == 0)) { 746 q = g_quark_from_static_string ("avfasset-src-error-quark"); 747 } 748 return q; 749} 750 751static GstURIType 752gst_avf_asset_src_uri_get_type (GType type) 753{ 754 return GST_URI_SRC; 755} 756 757static const gchar * const * 758gst_avf_asset_src_uri_get_protocols (GType type) 759{ 760 static const gchar * const protocols[] = { "file", "ipod-library", NULL }; 761 762 return protocols; 763} 764 765static gchar * 766gst_avf_asset_src_uri_get_uri (GstURIHandler * handler) 767{ 768 GstAVFAssetSrc *self = GST_AVF_ASSET_SRC (handler); 769 770 return g_strdup (self->uri); 771} 772 773static gboolean 774gst_avf_asset_src_uri_set_uri (GstURIHandler * handler, const gchar * uri, GError **error) 775{ 776 GstAVFAssetSrc *self = GST_AVF_ASSET_SRC (handler); 777 NSString *str; 778 NSURL *url; 779 AVAsset *asset; 780 gboolean ret = FALSE; 781 782 str = [NSString stringWithUTF8String: uri]; 783 url = [[NSURL alloc] initWithString: str]; 784 asset = [AVAsset assetWithURL: url]; 785 786 if (asset.playable) { 787 ret = TRUE; 788 g_free (self->uri); 789 self->uri = g_strdup (uri); 790 } else { 791 g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, 792 "Invalid URI '%s' for avfassetsrc", uri); 793 } 794 return ret; 795} 796 797static void 798gst_avf_asset_src_uri_handler_init (gpointer g_iface, gpointer iface_data) 799{ 800 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; 801 802 iface->get_type = gst_avf_asset_src_uri_get_type; 803 iface->get_protocols = gst_avf_asset_src_uri_get_protocols; 804 iface->get_uri = gst_avf_asset_src_uri_get_uri; 805 iface->set_uri = gst_avf_asset_src_uri_set_uri; 806} 807 808@implementation GstAVFAssetReader 809 810@synthesize duration; 811@synthesize position; 812 813- (NSDictionary *) capsToAudioSettings 814{ 815 gint depth; 816 gboolean isFloat; 817 GstAudioInfo info; 818 819 if (!gst_caps_is_fixed (audio_caps)) 820 return NULL; 821 822 gst_audio_info_from_caps (&info, audio_caps); 823 isFloat = GST_AUDIO_INFO_IS_FLOAT(&info); 824 depth = GST_AUDIO_INFO_DEPTH(&info); 825 826 return [NSDictionary dictionaryWithObjectsAndKeys: 827 [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey, 828 [NSNumber numberWithFloat:info.rate], AVSampleRateKey, 829 [NSNumber numberWithInt:info.channels], AVNumberOfChannelsKey, 830 //[NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], 831 //AVChannelLayoutKey, 832 [NSNumber numberWithInt:depth], AVLinearPCMBitDepthKey, 833 [NSNumber numberWithBool:isFloat],AVLinearPCMIsFloatKey, 834 [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved, 835 [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey, 836 nil]; 837} 838 839- (void) releaseReader 840{ 841 video_track = nil; 842 audio_track = nil; 843 video_tracks = nil; 844 audio_tracks = nil; 845 reader = nil; 846} 847 848- (void) initReader: (GError **) error 849{ 850 NSError *nserror; 851 852 reader = [[AVAssetReader alloc] initWithAsset:asset error:&nserror]; 853 if (nserror != NULL) { 854 GST_ERROR ("Error initializing reader: %s", 855 [nserror.description UTF8String]); 856 *error = g_error_new (GST_AVF_ASSET_SRC_ERROR, GST_AVF_ASSET_ERROR_INIT, "%s", 857 [nserror.description UTF8String]); 858 859 return; 860 } 861 862 audio_tracks = [asset tracksWithMediaType:AVMediaTypeAudio]; 863 video_tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; 864 reader.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration); 865 GST_INFO ("Found %lu video tracks and %lu audio tracks", 866 (unsigned long)[video_tracks count], (unsigned long)[audio_tracks count]); 867} 868 869- (id) initWithURI:(gchar*)uri : (GError **)error; 870{ 871 NSString *str; 872 NSURL *url; 873 874 GST_INFO ("Initializing AVFAssetReader with uri: %s", uri); 875 *error = NULL; 876 877 str = [NSString stringWithUTF8String: uri]; 878 url = [[NSURL alloc] initWithString: str]; 879 asset = [AVAsset assetWithURL: url]; 880 881 if (!asset.playable) { 882 *error = g_error_new (GST_AVF_ASSET_SRC_ERROR, GST_AVF_ASSET_ERROR_NOT_PLAYABLE, 883 "Media is not playable"); 884 asset = nil; 885 return nil; 886 } 887 888 selected_audio_track = -1; 889 selected_video_track = -1; 890 reading = FALSE; 891 position = 0; 892 duration = CMTIME_TO_GST_TIME (asset.duration); 893 894 /* FIXME: use fixed caps here until we found a way to determine 895 * the native audio format */ 896 audio_caps = gst_caps_from_string ("audio/x-raw, " 897 "format=F32LE, rate=44100, channels=2, layout=interleaved"); 898 899 [self initReader: error]; 900 if (*error) { 901 return nil; 902 } 903 904 self = [super init]; 905 return self; 906} 907 908- (BOOL) selectTrack: (GstAVFAssetReaderMediaType) type : (gint) index 909{ 910 NSArray *tracks; 911 AVAssetTrack *track; 912 AVAssetReaderOutput * __strong *output; 913 NSDictionary *settings; 914 NSString *mediaType; 915 gint *selected_track; 916 917 GST_INFO ("Selecting %s track %d", MEDIA_TYPE_TO_STR(type), index); 918 919 if (type == GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO) { 920 mediaType = AVMediaTypeAudio; 921 selected_track = &selected_audio_track; 922 output = &audio_track; 923 settings = [self capsToAudioSettings]; 924 } else if (type == GST_AVF_ASSET_READER_MEDIA_TYPE_VIDEO) { 925 mediaType = AVMediaTypeVideo; 926 selected_track = &selected_video_track; 927 output = &video_track; 928 settings = [NSDictionary dictionaryWithObjectsAndKeys: 929 [NSNumber numberWithInt: 930 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange], 931 kCVPixelBufferPixelFormatTypeKey, nil]; 932 } else { 933 return FALSE; 934 } 935 936 tracks = [asset tracksWithMediaType:mediaType]; 937 if ([tracks count] == 0 || [tracks count] < index + 1) { 938 return FALSE; 939 } 940 941 track = [tracks objectAtIndex:index]; 942 *selected_track = index; 943 *output = [AVAssetReaderTrackOutput 944 assetReaderTrackOutputWithTrack:track 945 outputSettings:settings]; 946 [reader addOutput:*output]; 947 return TRUE; 948} 949 950- (void) start: (GError **)error 951{ 952 if (reading) 953 return; 954 955 if (![reader startReading]) { 956 *error = g_error_new (GST_AVF_ASSET_SRC_ERROR, GST_AVF_ASSET_ERROR_START, 957 "%s", [reader.error.description UTF8String]); 958 reading = FALSE; 959 return; 960 } 961 reading = TRUE; 962} 963 964- (void) stop 965{ 966 [reader cancelReading]; 967 reading = FALSE; 968} 969 970- (BOOL) hasMediaType: (GstAVFAssetReaderMediaType) type 971{ 972 if (type == GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO) { 973 return [audio_tracks count] != 0; 974 } 975 if (type == GST_AVF_ASSET_READER_MEDIA_TYPE_VIDEO) { 976 return [video_tracks count] != 0; 977 } 978 return FALSE; 979} 980 981- (void) seekTo: (guint64) startTS : (guint64) stopTS : (GError **) error 982{ 983 CMTime startTime = kCMTimeZero, stopTime = kCMTimePositiveInfinity; 984 985 if (startTS != GST_CLOCK_TIME_NONE) { 986 startTime = CMTimeMake (startTS, GST_SECOND); 987 } 988 if (stopTS != GST_CLOCK_TIME_NONE) { 989 stopTime = CMTimeMake (stopTS, GST_SECOND); 990 } 991 992 /* AVFAssetReader needs to be recreated before changing the 993 * timerange property */ 994 [self stop]; 995 [self releaseReader]; 996 [self initReader: error]; 997 if (*error) { 998 return; 999 } 1000 1001 GST_DEBUG ("Seeking to start:%" GST_TIME_FORMAT " stop:%" GST_TIME_FORMAT, 1002 GST_TIME_ARGS(startTS), GST_TIME_ARGS(stopTS)); 1003 1004 reader.timeRange = CMTimeRangeMake(startTime, stopTime); 1005 [self selectTrack: GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO:selected_audio_track]; 1006 [self selectTrack: GST_AVF_ASSET_READER_MEDIA_TYPE_VIDEO:selected_video_track]; 1007 [self start: error]; 1008} 1009 1010- (GstBuffer *) nextBuffer: (GstAVFAssetReaderMediaType) type : (GError **) error 1011{ 1012 CMSampleBufferRef cmbuf; 1013 AVAssetReaderTrackOutput *areader = NULL; 1014 GstBuffer *buf; 1015 CMTime dur, ts; 1016 1017 GST_LOG ("Reading %s next buffer", MEDIA_TYPE_TO_STR (type)); 1018 if (type == GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO && audio_track != NULL) { 1019 areader = audio_track; 1020 } else if (type == GST_AVF_ASSET_READER_MEDIA_TYPE_VIDEO && 1021 video_track != NULL) { 1022 areader = video_track; 1023 } 1024 1025 if (areader == NULL) { 1026 return NULL; 1027 } 1028 1029 *error = NULL; 1030 cmbuf = [areader copyNextSampleBuffer]; 1031 if (cmbuf == NULL) { 1032 if (reader.error != NULL) { 1033 *error = g_error_new (GST_AVF_ASSET_SRC_ERROR, GST_AVF_ASSET_ERROR_READ, 1034 "%s", [reader.error.description UTF8String]); 1035 } 1036 /* EOS */ 1037 return NULL; 1038 } 1039 1040 buf = gst_core_media_buffer_new (cmbuf, FALSE, NULL); 1041 CFRelease (cmbuf); 1042 if (buf == NULL) 1043 return NULL; 1044 /* cmbuf is now retained by buf (in meta) */ 1045 dur = CMSampleBufferGetDuration (cmbuf); 1046 ts = CMSampleBufferGetPresentationTimeStamp (cmbuf); 1047 if (dur.value != 0) { 1048 GST_BUFFER_DURATION (buf) = CMTIME_TO_GST_TIME (dur); 1049 } 1050 GST_BUFFER_TIMESTAMP (buf) = CMTIME_TO_GST_TIME (ts); 1051 GST_LOG ("Copying next %s buffer ts:%" GST_TIME_FORMAT " dur:%" 1052 GST_TIME_FORMAT, MEDIA_TYPE_TO_STR (type), 1053 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP (buf)), 1054 GST_TIME_ARGS(GST_BUFFER_DURATION (buf))); 1055 if (GST_BUFFER_TIMESTAMP (buf) > position) { 1056 position = GST_BUFFER_TIMESTAMP (buf); 1057 } 1058 return buf; 1059} 1060 1061- (GstCaps *) getCaps: (GstAVFAssetReaderMediaType) type 1062{ 1063 GstCaps *caps = NULL; 1064 AVAssetTrack *track; 1065 1066 if (type == GST_AVF_ASSET_READER_MEDIA_TYPE_AUDIO) { 1067 caps = gst_caps_ref (audio_caps); 1068 GST_INFO ("Using audio caps: %" GST_PTR_FORMAT, caps); 1069 } else if (type == GST_AVF_ASSET_READER_MEDIA_TYPE_VIDEO) { 1070 gint fr_n, fr_d; 1071 1072 track = [video_tracks objectAtIndex: selected_video_track]; 1073 gst_util_double_to_fraction(track.nominalFrameRate, &fr_n, &fr_d); 1074 caps = gst_caps_new_simple ("video/x-raw", 1075 "format", G_TYPE_STRING, "NV12", 1076 "width", G_TYPE_INT, (int) track.naturalSize.width, 1077 "height", G_TYPE_INT, (int) track.naturalSize.height, 1078 "framerate", GST_TYPE_FRACTION, fr_n, fr_d, NULL); 1079 GST_INFO ("Using video caps: %" GST_PTR_FORMAT, caps); 1080 video_caps = gst_caps_ref (caps); 1081 } 1082 1083 return caps; 1084} 1085 1086- (void) dealloc 1087{ 1088 asset = nil; 1089 [self releaseReader]; 1090 1091 if (audio_caps != NULL) { 1092 gst_caps_unref (audio_caps); 1093 } 1094 1095 if (video_caps != NULL) { 1096 gst_caps_unref (audio_caps); 1097 } 1098} 1099 1100@end 1101