{"id":21694,"date":"2018-03-14T17:25:13","date_gmt":"2018-03-14T17:25:13","guid":{"rendered":"http:\/\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial"},"modified":"2025-03-08T15:05:08","modified_gmt":"2025-03-08T23:05:08","slug":"converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial","title":{"rendered":"How to Convert Android Video to Animated GIF"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Cloudinary is a cloud-based, end-to-end solution for downloading, storing, editing, optimizing, and delivering images and videos. Note that editing means that you can transform images and <a href=\"https:\/\/cloudinary.com\/blog\/optimizing_video_with_cloudinary_and_the_html5_video_player_part_1\">videos<\/a>, that is, resize and add numerous effects to them.<\/p>\n<p>Images encoded in graphics interchange format (GIF) are called animated GIFs, which contain  images or frames in a single file with a description from its own graphic-control extension. To convey animation, the frames appear in a specific order. With Cloudinary, you can also add various effects to the generated GIFs and deliver them by means of unique URLs.<\/p>\n<p>This is part of a series of articles about <a href=\"https:\/\/cloudinary.com\/guides\/web-performance\/video-optimization-why-you-need-it-and-5-critical-best-practices\">video optimization<\/a>.<\/p>\n<h2>Convert Video to Animated GIF<\/h2>\n<p>This tutorial shows you how to build an Android app in Android Studio through Cloudinary and then convert a <a href=\"https:\/\/cloudinary.com\/video_api\">video<\/a> to animated GIF, ready for download.<\/p>\n<h3>App Flow<\/h3>\n<p>The process is seamless and simple:<\/p>\n<ol>\n<li>You select and load a video into the app, which then automatically uploads it to Cloudinary.<\/li>\n<li>Cloudinary processes the video and converts it to a GIF.<\/li>\n<li>Cloudinary displays it on screen for download.<\/li>\n<\/ol>\n<p>Tip: You can take advantage of the same process to reversely convert a WebM file to an MP4 file.<\/p>\n<p>As background reference, see this Cloudinary post on <a href=\"https:\/\/cloudinary.com\/blog\/easy_image_loading_and_optimization_with_cloudinary_and_fresco\">image loading and optimization with Cloudinary and Fresco <\/a>.<\/p>\n<h3>Requirements<\/h3>\n<p>As a prerequisite, you must be conversant with the Android development and third-party libraries. You also need the following:<\/p>\n<ul>\n<li>A <a href=\"https:\/\/cloudinary.com\/users\/register\/free\">Cloudinary account<\/a>\n<\/li>\n<li>The <a href=\"https:\/\/cloudinary.com\/documentation\/android_integration\">Cloudinary Android SDK<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/developer.android.com\/studio\/install.html\">Android Studio<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/github.com\/bumptech\/glide\">Glide<\/a>, the library for asynchronous image loading<\/li>\n<\/ul>\n<h3>Demo App<\/h3>\n<p>These two short clips show how the demo app (called the app in the rest of this tutorial) works:<\/p>\n<img decoding=\"async\" src=\"https:\/\/cloudinary-res.cloudinary.com\/video\/upload\/w_300,c_fill,e_loop\/mp4togif.gif\" alt=\"mp4 to gif\" width=\"45%\" style=\"margin-right: 6%;\"\/>\n<img decoding=\"async\" src=\"https:\/\/cloudinary-res.cloudinary.com\/video\/upload\/w_300,c_fill,e_loop\/Image_board-upload.gif\" alt=\"image board\" width=\"45%\"\/>\n<p>Here is the <a href=\"https:\/\/github.com\/Kennypee\/Build-Your-Own-Android-Video-To-Gif-Converter-With-Cloudinary\">source code.<\/a><\/p>\n<p>To try out the app on an Android device, <a href=\"https:\/\/drive.google.com\/file\/d\/16TD1MOQAGNqO3sJKZ4BPz7pkTpshceG2\/view?usp=sharing\">download it first.<\/a><\/p>\n<h3>Setup of the Android Environment<\/h3>\n<p>Set up an environment with Android Studio by following <a href=\"https:\/\/developer.android.com\/topic\/instant-apps\/getting-started\/setup.html\">this procedure .<\/a><\/p>\n<h3>Setup of Dependencies<\/h3>\n<p>Once you\u2019ve set up your app in Android Studio or an IDE of your choice, install Cloudinary and Glide as dependencies in the <code>build.gradle<\/code> file of your app module by first adding this code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">implementation group: <span class=\"hljs-string\">'com.cloudinary'<\/span>, <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'cloudinary-android'<\/span>, <span class=\"hljs-attr\">version<\/span>: <span class=\"hljs-string\">'1.22.0'<\/span>\nimplementation <span class=\"hljs-string\">'com.squareup.picasso:picasso:2.5.2'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, click Sync to install the dependencies. Afterward, open the <code>AndroidManifest.xml<\/code> file and add the Cloudinary configurations to the <code>application<\/code> tag:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">manifest<\/span> <span class=\"hljs-attr\">xmlns:android<\/span>=<span class=\"hljs-string\">\"https:\/\/schemas.android.com\/apk\/res\/android\"<\/span>\n       <span class=\"hljs-attr\">package<\/span>=<span class=\"hljs-string\">\"com.example.ekene.imageboardcloudinary\"<\/span>&gt;<\/span>\n    \n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">uses-permission<\/span> <span class=\"hljs-attr\">android:name<\/span>=<span class=\"hljs-string\">\"android.permission.INTERNET\"<\/span>\/&gt;<\/span>\n    \n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">application<\/span>\n            <span class=\"hljs-attr\">...<\/span>\n            &gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta-data<\/span>\n                <span class=\"hljs-attr\">android:name<\/span>=<span class=\"hljs-string\">\"CLOUDINARY_URL\"<\/span>\n                <span class=\"hljs-attr\">android:value<\/span>=<span class=\"hljs-string\">\"cloudinary:\/\/@myCloudName\"<\/span>\/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">application<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">manifest<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Replace <code>myCloudName<\/code> with your Cloudinary name, as displayed on your <a href=\"https:\/\/cloudinary.com\/users\/login\">console<\/a>. Note that the Internet permissions are already specified under <code>users-permission<\/code> in the above code.<\/p>\n<h3>App Layout<\/h3>\n<p>Now define the app layout with the following user-interface elements:<\/p>\n<p>A bar that shows the progress of the upload process\nA button that triggers the video upload\nAn <code>ImageView<\/code> object that renders the GIF created with Cloudinary\nA button for downloading the GIF<\/p>\n<p>Next, edit the <code>activity_main.xml<\/code> file to make it read like this:<\/p>\n<p><a href=\"https:\/\/gist.github.com\/christiannwamba\/e18e0d3e972087e5e50522f79cd1cfa3\">Activity content on Gist<\/a><\/p>\n<p>Afterwards, initialize the view objects in the <code>MainActivity.java<\/code> file so you can refer to them. Make the file read as follows:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">    package com.example.ekene.mp4togifconverter;\n    import ...\n    \n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MainActivity<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">AppCompatActivity<\/span> <\/span>{\n    \n        <span class=\"hljs-keyword\">private<\/span> Button uploadBtn;\n        <span class=\"hljs-keyword\">private<\/span> ProgressBar progressBar;\n        <span class=\"hljs-keyword\">private<\/span> int SELECT_VIDEO = <span class=\"hljs-number\">2<\/span>;\n        <span class=\"hljs-keyword\">private<\/span> ImageView img1;\n        <span class=\"hljs-keyword\">private<\/span> DownloadManager downloadManager;\n        <span class=\"hljs-keyword\">private<\/span> Button download_btn;\n        <span class=\"hljs-keyword\">private<\/span> String gifUrl;\n    \n        @Override\n        <span class=\"hljs-keyword\">protected<\/span> void onCreate(Bundle savedInstanceState) {\n            super.onCreate(savedInstanceState);\n            setContentView(R.layout.activity_main);\n    \n            progressBar = findViewById(R.id.progress_bar);\n            MediaManager.init(this);\n            img1 = findViewById(R.id.img1);\n            uploadBtn = findViewById(R.id.uploadBtn);\n            download_btn = findViewById(R.id.download_btn);\n            download_btn.setVisibility(View.INVISIBLE);\n            <span class=\"hljs-comment\">\/\/...<\/span>\n                  \n            }\n    }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now define the button for uploads such that, on a click, it launches the gallery from which you can select a video for upload:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    package com.example.ekene.mp4togifconverter;\n    <span class=\"hljs-keyword\">import<\/span> ...\n    public <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MainActivity<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">AppCompatActivity<\/span> <\/span>{\n        private Button uploadBtn;\n        @Override\n        protected <span class=\"hljs-keyword\">void<\/span> onCreate(Bundle savedInstanceState) {\n            <span class=\"hljs-keyword\">super<\/span>.onCreate(savedInstanceState);\n            setContentView(R.layout.activity_main);\n            uploadBtn = findViewById(R.id.uploadBtn);        \n            uploadBtn.setOnClickListener(<span class=\"hljs-keyword\">new<\/span> View.OnClickListener() {\n            @Override\n            public <span class=\"hljs-keyword\">void<\/span> onClick(View view) {\n                pickVideoFromGallery();\n        \n          }\n        private <span class=\"hljs-keyword\">void<\/span> pickVideoFromGallery() {\n            Intent GalleryIntent = <span class=\"hljs-keyword\">new<\/span> Intent();\n            GalleryIntent.setType(<span class=\"hljs-string\">\"video\/*\"<\/span>);\n            GalleryIntent.setAction(Intent.ACTION_GET_CONTENT);\n            startActivityForResult(Intent.createChooser(GalleryIntent, \n            <span class=\"hljs-string\">\"select video\"<\/span>), SELECT_VIDEO);\n        }\n    });\n    <span class=\"hljs-comment\">\/\/...<\/span>\n    }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Subsequently, as soon as you select a video, Cloudinary calls the <code>onActivityResult<\/code> method, which in turn triggers an upload to Cloudinary. To facilitate uploads, create an <code>UploadRequest<\/code> method and dispatch it within the <code>onActivityResult<\/code> method, as described in the next section.<\/p>\n<p>Meantime, to enable network requests, open the <code>AndroidManifest.xml<\/code> file and add this code for internet permissions just above the <code>Application<\/code> tag:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">uses-permission<\/span> <span class=\"hljs-attr\">android:name<\/span>=<span class=\"hljs-string\">\"android.permission.INTERNET\"<\/span>\/&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h2>Cloudinary Uploads<\/h2>\n<p>Cloudinary offers two types of uploads:<\/p>\n<p><a href=\"https:\/\/cloudinary.com\/documentation\/android_image_and_video_upload#signed_upload\">Signed<\/a> uploads, which require an authentication signature from a backend. For these uploads, your images and videos are signed with the API and secret key in the console. Because those signatures are risky on the client side, which can be easily decompiled, a back-end is mandatory for security.<\/p>\n<p><a href=\"https:\/\/cloudinary.com\/documentation\/android_image_and_video_upload#unsigned_upload\">Unsigned<\/a> uploads, which do not require signatures and are thus less secure than signed ones. These uploads are controlled by an upload preset, which defines the options that apply to the images that are uploaded with the preset.<\/p>\n<p>This app features unsigned uploads. To enable them on the console, click Settings on your dashboard, select the Upload tab, scroll down to Upload presets, and enable Unsigned. Cloudinary then generates a preset with a random string as its name. Copy the name and set it aside for use late.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-res.cloudinary.com\/image\/upload\/w_700,c_fill,f_auto,q_auto\/unsigned.jpg\" alt=\"Unsigned\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"700\" height=\"451\"\/><\/p>\n<p>For more details on creating Android apps with unsigned uploads, see this <a href=\"https:\/\/cloudinary.com\/blog\/impressed_by_whatsapp_technology_build_a_whatsapp_clone_with_image_and_video_upload\">Cloudinary post<\/a>.<\/p>\n<p>To enable the upload of a selected video to Cloudinary, initialize the Cloudinary <code>MediaManager<\/code> class <code>onCreate<\/code> method in the <code>MainActivity<\/code> class, as shown here:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    package com.example.ekene.mp4togifconverter;\n    <span class=\"hljs-keyword\">import<\/span> ...\n    public <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MainActivity<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">AppCompatActivity<\/span> <\/span>{\n        @Override\n        protected <span class=\"hljs-keyword\">void<\/span> onCreate(Bundle savedInstanceState) {\n            <span class=\"hljs-keyword\">super<\/span>.onCreate(savedInstanceState);\n            setContentView(R.layout.activity_main);\n            <span class=\"hljs-comment\">\/\/initialize MediaManager<\/span>\n            MediaManager.init(<span class=\"hljs-keyword\">this<\/span>);\n        }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, call the <code>onActivityResult()<\/code> method in <code>MainActivity<\/code> and set it up.<\/p>\n<p>As background, here are the methods in <code>MainActivity<\/code> this app has adopted so far and their relationships to <code>onActivityResult<\/code>:<\/p>\n<ul>\n<li>\n<p><code>onCreate<\/code> \u2014 Becomes active when the app starts. The XML file in use earlier is the default layout of the activity. You also added a listener to the button, which, on a click, causes the app to call the second method, <code>pickVideoFromGallery<\/code> (see below).<\/p>\n<\/li>\n<li>\n<p><code>pickVideoFromGallery<\/code> \u2014 Launches the user\u2019s gallery for video selection. This process generates a unique request code in the <code>SELECT_VIDEO<\/code> variable. Because a response follows a video section, the <code>startActivityForResult()<\/code> method renders the response on the <code>onActivityForResult()<\/code> method. If the selection succeeds, so does the response, and the <code>selectedVideo<\/code> variable in turn holds <code>URI<\/code> of the selected video for upload. Finally, Culinary calls the <code>onActivityForResult()<\/code> method (see below). If the selection fails, the process ends.<\/p>\n<\/li>\n<li>\n<p><code>onActivityForResult()<\/code>  \u2014 Checks if the response from <code>startActivityForResult()<\/code> succeeded. On a video selection, <code>resultCode<\/code> is equal to <code>Activity.RESULT_OK<\/code>; otherwise, to <code>Activity.RESULT_CANCELLED<\/code>. A success results in an upload request to Cloudinary with <code>MediaManager<\/code>, like this:<\/p>\n<\/li>\n<\/ul>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">    @Override\n    <span class=\"hljs-keyword\">protected<\/span> void onActivityResult(int requestCode, int resultCode, <span class=\"hljs-keyword\">final<\/span> Intent data) {\n        <span class=\"hljs-keyword\">if<\/span> (requestCode == SELECT_VIDEO &amp;&amp; resultCode == RESULT_OK) {\n            Uri selectedVideo = data.getData();\n            <span class=\"hljs-comment\">\/\/...<\/span>\n            }\n        }\n        \n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now create an upload request by adding <code>MediaManager<\/code> to <code>onActivityResult<\/code> and build <code>UploadRequest<\/code> in Cloudinary with the following five methods:<\/p>\n<ul>\n<li>\n<code>upload()<\/code> \u2014 Takes in <code>uri<\/code> of the selected video for uploads.<\/li>\n<li>\n<code>unsigned()<\/code> \u2013 Takes in <code>preset name<\/code> from your console.<\/li>\n<li>\n<code>option()<\/code> \u2013 Takes in <code>resource_type<\/code> of the upload:<\/li>\n<\/ul>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">    @Override\n    <span class=\"hljs-keyword\">protected<\/span> void onActivityResult(int requestCode, int resultCode, <span class=\"hljs-keyword\">final<\/span> Intent data) {\n        <span class=\"hljs-keyword\">if<\/span> (requestCode == SELECT_VIDEO &amp;&amp; resultCode == RESULT_OK) {\n            Uri selectedVideo = data.getData();\n            MediaManager.get()\n                    .upload(selectedVideo)\n                    .unsigned(<span class=\"hljs-string\">\"preset_name\"<\/span>)\n                    .option(<span class=\"hljs-string\">\"resource_type\"<\/span>, <span class=\"hljs-string\">\"video\"<\/span>)\n                    .callback(...)\n                   <span class=\"hljs-comment\">\/\/...<\/span>\n                   }\n     }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ul>\n<li>\n<code>callback()<\/code> \u2014 Takes in a new <code>UploadCallback<\/code> method, which implements several other callback methods that track the progress of the upload.<\/li>\n<li>\n<code>onStart()<\/code> \u2014 Defines what happens when upload starts:<\/li>\n<\/ul>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    .callback(<span class=\"hljs-keyword\">new<\/span> UploadCallback() {\n                        @Override\n                        public <span class=\"hljs-keyword\">void<\/span> onStart(<span class=\"hljs-built_in\">String<\/span> requestId) {\n                            progressBar.setVisibility(View.VISIBLE);\n                            Toast.makeText(MainActivity.this, \n                            <span class=\"hljs-string\">\"Upload has started ...\"<\/span>, Toast.LENGTH_SHORT).show();\n                        }\n                        <span class=\"hljs-comment\">\/\/...<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The above code makes <code>progressBar<\/code> visible and sets <code>Toast<\/code>, which displays the message \u201cUpload has started\u201d<\/p>\n<ul>\n<li>\n<code>onProgress()<\/code> \u2014 Defines what happens as the upload progresses, that is, has started but not yet completed. Leave it blank in this app:<\/li>\n<\/ul>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    .callback(<span class=\"hljs-keyword\">new<\/span> UploadCallback() {\n                       @Override\n                        public <span class=\"hljs-keyword\">void<\/span> onProgress(...) {\n                        }\n                        <span class=\"hljs-comment\">\/\/...<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ul>\n<li>\n<code>onSuccess()<\/code> \u2014 Defines what happens if the video upload succeeds. In this app, you generate the GIF from the uploaded video and pass it to the <code>ImageView<\/code> object with Glide, where the conversion occurs.<\/li>\n<\/ul>\n<h2>Conversion<\/h2>\n<p>After upload to Cloudinary, the video is assigned a unique ID by Cloudinary. You refer to the ID when editing the video. Here, since you have already uploaded the video, all you need to do is append <code>.gif<\/code> to its unique ID: <code>(publicId+&quot;.gif&quot;);<\/code>. Easy as pie!<\/p>\n<p>To learn more about animated GIFs and the related best practices, see the Cloudinary post <a href=\"https:\/\/cloudinary.com\/blog\/evolution_of_img_gif_without_the_gif\">Evolution of <code>&lt;img&gt;<\/code><\/a>.<\/p>\n<p>Next, pass the converted GIF to the <code>MediaManager<\/code>\u2019s <code>generate()<\/code> method, which then returns a URL for the GIF. Subsequently, pass the URL to the <code>load()<\/code> method of your Glide object and call the <code>asGif()<\/code> method to render it on screen as a GIF, like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    .callback(<span class=\"hljs-keyword\">new<\/span> UploadCallback() {\n                        @Override\n    public <span class=\"hljs-keyword\">void<\/span> onSuccess(<span class=\"hljs-built_in\">String<\/span> requestId, <span class=\"hljs-built_in\">Map<\/span> resultData) {\n    \n        Toast.makeText(MainActivity.this, <span class=\"hljs-string\">\"Uploaded Succesfully\"<\/span>, \n        Toast.LENGTH_SHORT).show();\n        progressBar.setVisibility(View.GONE);\n        uploadBtn.setVisibility(View.INVISIBLE);\n    \n        <span class=\"hljs-built_in\">String<\/span> publicId = resultData.get(<span class=\"hljs-string\">\"public_id\"<\/span>).toString();\n    \n        gifUrl = MediaManager.get().url().resourceType(<span class=\"hljs-string\">\"video\"<\/span>)\n                .transformation(<span class=\"hljs-keyword\">new<\/span> Transformation().videoSampling(<span class=\"hljs-string\">\"25\"<\/span>)\n                .delay(<span class=\"hljs-string\">\"200\"<\/span>).height(<span class=\"hljs-number\">200<\/span>).effect(<span class=\"hljs-string\">\"loop:10\"<\/span>).crop(<span class=\"hljs-string\">\"scale\"<\/span>))\n                .format(<span class=\"hljs-string\">\"gif\"<\/span>).generate(publicId);\n    \n        Glide.with(getApplicationContext()).asGif().load(gifUrl).into(img1);\n        download_btn.setVisibility(View.VISIBLE);\n    \n    }\n                          <span class=\"hljs-comment\">\/\/...<\/span>\n      }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Access the URL of the uploaded video by calling <code>resultData.get(&quot;url&quot;)<\/code>. To access the video ID, call <code>resultData.get(&quot;public_id&quot;)<\/code>. Refer to that ID when you manipulate the video and generate a GIF, whose resulting URL you then store in a string variable.<\/p>\n<p>Afterwards, load the GIF with Glide into the <code>ImageView<\/code> object by means of these two methods:<\/p>\n<ul>\n<li>\n<code>onError()<\/code> \u2014 Defines what happens if an error occurs during the upload process. For this app, create a <code>Toast<\/code> method for the error message, like this:<\/li>\n<\/ul>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    .callback(<span class=\"hljs-keyword\">new<\/span> UploadCallback() {\n                        @Override\n                        public <span class=\"hljs-keyword\">void<\/span> onError(<span class=\"hljs-built_in\">String<\/span> requestId, ErrorInfo error) {\n                            Toast.makeText(MainActivity.this, \n                            <span class=\"hljs-string\">\"Upload Error\"<\/span>, Toast.LENGTH_SHORT).show();\n                            Log.v(<span class=\"hljs-string\">\"ERROR!!\"<\/span>, error.getDescription());\n                        }\n                        <span class=\"hljs-comment\">\/\/...<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ul>\n<li>\n<code>dispatch()<\/code> \u2014 Defines when and how each upload request runs.<\/li>\n<\/ul>\n<p>You have now set up the <code>onActivityForResult()<\/code> method. When it receives a response from <code>pickVideoFromGallery()<\/code>, it creates an upload request to Cloudinary with the URI of the selected video. Once the upload succeeds, <code>onActivityForResult()<\/code> converts the video to a GIF and renders it on the <code>ImageView<\/code> object, which you defined earlier. That is a more robust process than that performed by the conventional Android video editor.<\/p>\n<p>Try it out: run the app to test the upload, conversion, and rendering process.<\/p>\n<p>In case of errors, have a look at the <a href=\"https:\/\/github.com\/Kennypee\/ImageBoard-CLoudinary\">source code<\/a>. Long code lines can be overwhelming sometimes.<\/p>\n<h2>GIF Downloads<\/h2>\n<p>Finally, set up the <code>download_btn<\/code> method for downloading converted GIFs. Actually, you\u2019ve already initialized <code>download_btn<\/code> in the <code>MainActivity<\/code> file, as follows:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    package com.example.ekene.mp4togifconverter;\n    <span class=\"hljs-keyword\">import<\/span> ...\n    public <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MainActivity<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">AppCompatActivity<\/span> <\/span>{\n        private Button download_btn;\n        @Override\n        protected <span class=\"hljs-keyword\">void<\/span> onCreate(Bundle savedInstanceState) {\n            <span class=\"hljs-keyword\">super<\/span>.onCreate(savedInstanceState);\n            setContentView(R.layout.activity_main);\n            download_btn = findViewById(R.id.download_btn);\n            download_btn.setVisibility(View.INVISIBLE);        \n       \n            download_btn.setOnClickListener(<span class=\"hljs-keyword\">new<\/span> View.OnClickListener() {\n                @Override\n                public <span class=\"hljs-keyword\">void<\/span> onClick(View view) {\n            \n                    downloadManager = (DownloadManager)getSystemService(\n                    Context.DOWNLOAD_SERVICE);\n                    Uri uri = Uri.parse(gifUrl);\n                    DownloadManager.Request request = <span class=\"hljs-keyword\">new<\/span> DownloadManager.Request(uri);\n                    request.setNotificationVisibility(\n                    DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);\n                    Long reference = downloadManager.enqueue(request);\n                }\n            });\n            <span class=\"hljs-comment\">\/\/...<\/span>\n      }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You\u2019re now all set. On a click of the download button, <code>download_btn<\/code> parses the URI of the GIF to the Android Download Manager, which in turn enqueues a download request, displaying the notifications, as appropriate, as the process progresses.<\/p>\n<h2>Conclusion<\/h2>\n<p>After familiarizing yourself with this tutorial, you can leverage <a href=\"https:\/\/cloudinary.com\/users\/register\/free\">Cloudinary\u2019s<\/a> superb capabilities for transforming and optimizing images and videos into more appealing, compact visuals and for generating GIFs from videos on the fly. For more details, see our <a href=\"https:\/\/cloudinary.com\/documentation\">documentation.<\/a><\/p>\n<p>Problems with the tutorial? Describe them under Comments below; I\u2019ll respond as soon as I can.<\/p>\n<hr \/>\n<h2>Want to Learn More About Video Optimization?<\/h2>\n<ul>\n<li>\n<a href=\"https:\/\/cloudinary.com\/blog\/optimizing_video_with_cloudinary_and_the_html5_video_player_part_1\">Optimizing Video with Cloudinary and the HTML5 Video Player<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/cloudinary.com\/blog\/exoplayer_android_tutorial_easy_video_delivery_and_editing\">ExoPlayer Android Tutorial: Easy Video Delivery and Editing<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/cloudinary.com\/blog\/how_to_generate_waveform_images_from_audio_files\">How to Generate Waveform Images From Audio Files<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/cloudinary.com\/blog\/with_automatic_video_subtitles_silence_speaks_volumes\">Auto Generate Subtitles Based on Video Transcript<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/cloudinary.com\/blog\/auto_generate_video_previews_with_great_results_every_time\">Automated Generation of Intelligent Video Previews on Cloudinary\u2019s Dynamic Video Platform<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial\">Converting Android Videos to Animated GIF Images With Cloudinary: A Tutorial<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/cloudinary.com\/guides\/marketing-videos\/tips-for-retaining-audience-through-engaging-videos\">Tips for Retaining Audience Through Engaging Videos<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/cloudinary.com\/guides\/marketing-videos\/product-videos-101-what-makes-them-great\">Product Videos 101: What Makes Them Great?<\/a>\n<\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":21695,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[333,128,134,202,303,305],"class_list":["post-21694","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-android","tag-gif","tag-guest-post","tag-mobile","tag-video","tag-video-api"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>How to Convert Android Video to Animated GIF<\/title>\n<meta name=\"description\" content=\"Learn how to build Android apps that convert videos to animated GIFs with an option for user downloads.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Convert Android Video to Animated GIF\" \/>\n<meta property=\"og:description\" content=\"Learn how to build Android apps that convert videos to animated GIFs with an option for user downloads.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2018-03-14T17:25:13+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-08T23:05:08+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1649742402\/Web_Assets\/blog\/Android_MP4_to_GIF_Converter\/Android_MP4_to_GIF_Converter-jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"1540\" \/>\n\t<meta property=\"og:image:height\" content=\"847\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"How to Convert Android Video to Animated GIF\",\"datePublished\":\"2018-03-14T17:25:13+00:00\",\"dateModified\":\"2025-03-08T23:05:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial\"},\"wordCount\":8,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649742402\/Web_Assets\/blog\/Android_MP4_to_GIF_Converter\/Android_MP4_to_GIF_Converter.jpg?_i=AA\",\"keywords\":[\"Android\",\"GIF\",\"Guest Post\",\"Mobile\",\"Video\",\"Video API\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2018\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial\",\"url\":\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial\",\"name\":\"How to Convert Android Video to Animated GIF\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649742402\/Web_Assets\/blog\/Android_MP4_to_GIF_Converter\/Android_MP4_to_GIF_Converter.jpg?_i=AA\",\"datePublished\":\"2018-03-14T17:25:13+00:00\",\"dateModified\":\"2025-03-08T23:05:08+00:00\",\"description\":\"Learn how to build Android apps that convert videos to animated GIFs with an option for user downloads.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649742402\/Web_Assets\/blog\/Android_MP4_to_GIF_Converter\/Android_MP4_to_GIF_Converter.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649742402\/Web_Assets\/blog\/Android_MP4_to_GIF_Converter\/Android_MP4_to_GIF_Converter.jpg?_i=AA\",\"width\":1540,\"height\":847},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Convert Android Video to Animated GIF\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Convert Android Video to Animated GIF","description":"Learn how to build Android apps that convert videos to animated GIFs with an option for user downloads.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial","og_locale":"en_US","og_type":"article","og_title":"How to Convert Android Video to Animated GIF","og_description":"Learn how to build Android apps that convert videos to animated GIFs with an option for user downloads.","og_url":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial","og_site_name":"Cloudinary Blog","article_published_time":"2018-03-14T17:25:13+00:00","article_modified_time":"2025-03-08T23:05:08+00:00","og_image":[{"width":1540,"height":847,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1649742402\/Web_Assets\/blog\/Android_MP4_to_GIF_Converter\/Android_MP4_to_GIF_Converter-jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial"},"author":{"name":"","@id":""},"headline":"How to Convert Android Video to Animated GIF","datePublished":"2018-03-14T17:25:13+00:00","dateModified":"2025-03-08T23:05:08+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial"},"wordCount":8,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649742402\/Web_Assets\/blog\/Android_MP4_to_GIF_Converter\/Android_MP4_to_GIF_Converter.jpg?_i=AA","keywords":["Android","GIF","Guest Post","Mobile","Video","Video API"],"inLanguage":"en-US","copyrightYear":"2018","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial","url":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial","name":"How to Convert Android Video to Animated GIF","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649742402\/Web_Assets\/blog\/Android_MP4_to_GIF_Converter\/Android_MP4_to_GIF_Converter.jpg?_i=AA","datePublished":"2018-03-14T17:25:13+00:00","dateModified":"2025-03-08T23:05:08+00:00","description":"Learn how to build Android apps that convert videos to animated GIFs with an option for user downloads.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649742402\/Web_Assets\/blog\/Android_MP4_to_GIF_Converter\/Android_MP4_to_GIF_Converter.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649742402\/Web_Assets\/blog\/Android_MP4_to_GIF_Converter\/Android_MP4_to_GIF_Converter.jpg?_i=AA","width":1540,"height":847},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/converting_android_videos_to_animated_gif_images_with_cloudinary_a_tutorial#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Convert Android Video to Animated GIF"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649742402\/Web_Assets\/blog\/Android_MP4_to_GIF_Converter\/Android_MP4_to_GIF_Converter.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/21694","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=21694"}],"version-history":[{"count":7,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/21694\/revisions"}],"predecessor-version":[{"id":37166,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/21694\/revisions\/37166"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/21695"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=21694"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=21694"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=21694"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}