pnmenc: Tidy up code, support BE/LE GRAY16 properly
authorJan Schmidt <jan@centricular.com>
Wed, 18 May 2016 07:19:40 +0000 (17:19 +1000)
committerJan Schmidt <jan@centricular.com>
Mon, 23 May 2016 21:21:44 +0000 (07:21 +1000)
Remove code that dealt with odd strides separately - there's
not really any overhead to just using 1 codepath for both matched
and unmatched stride output.

Add separate codepaths for BE vs LE GRAY16 input so they're
handled properly

gst/pnm/gstpnmenc.c

index 8437499..0d9ea17 100644 (file)
@@ -189,12 +189,6 @@ gst_pnmenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
   guint i, j;
   guint maxbytes_per_pixel, str_len;
   gchar format_str[4];
-  union
-  {
-    guint8 *ui8;
-    guint16 *ui16;
-    gpointer ptr;
-  } data;
   pnmenc = GST_PNMENC (encoder);
   info = &pnmenc->input_state->info;
 
@@ -253,120 +247,116 @@ gst_pnmenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
     ret = GST_FLOW_ERROR;
     goto done;
   }
-  memcpy (omap.data, header, strlen (header));
-
+  /* Copy out the header first */
   head_size = strlen (header);
+  memcpy (omap.data, header, head_size);
+
   if (pnmenc->info.encoding == GST_PNM_ENCODING_ASCII) {
-    data.ptr = imap.data;
     /* We need to convert to ASCII */
-    if (pnmenc->info.width % 4 != 0) {
-      /* Convert from gstreamer rowstride to PNM rowstride */
-      if (pnmenc->info.type == GST_PNM_TYPE_PIXMAP) {
-        o_rowstride = 3 * pnmenc->info.width;
-      } else {
-        o_rowstride = pnmenc->info.width;
-      }
-
-      switch GST_VIDEO_INFO_FORMAT
-        (info) {
-        case GST_VIDEO_FORMAT_RGB:
-        case GST_VIDEO_FORMAT_GRAY8:
-          i_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (pnmenc->input_state, 0);
-          for (i = 0; i < pnmenc->info.height; i++) {
-            index = i * i_rowstride;
-            for (j = 0; j < o_rowstride; j++, bytes++, index++) {
-              g_snprintf ((char *) omap.data + head_size, maxbytes_per_pixel,
-                  format_str, data.ui8[index]);
-              head_size += str_len;
-              omap.data[head_size++] = ' ';
-              /* Add new line so that file will not end up with sinle big line */
-              if (!((bytes + 1) % 20))
-                omap.data[head_size++] = '\n';
-            }
-          }
-          break;
-        case GST_VIDEO_FORMAT_GRAY16_BE:
-        case GST_VIDEO_FORMAT_GRAY16_LE:
-          i_rowstride =
-              GST_VIDEO_FRAME_COMP_STRIDE (pnmenc->input_state, 0) / 2;
-          for (i = 0; i < pnmenc->info.height; i++) {
-            index = i * i_rowstride;
-            for (j = 0; j < o_rowstride; j++, bytes++, index++) {
-              g_snprintf ((char *) omap.data + head_size, maxbytes_per_pixel,
-                  format_str, data.ui16[index]);
-              head_size += str_len;
-              omap.data[head_size++] = ' ';
-              /* Add new line so that file will not end up with sinle big line */
-              if (!((bytes + 1) % 20))
-                omap.data[head_size++] = '\n';
-            }
+    /* Convert from gstreamer rowstride to PNM rowstride as we go */
+    if (pnmenc->info.type == GST_PNM_TYPE_PIXMAP) {
+      o_rowstride = 3 * pnmenc->info.width;
+    } else {
+      o_rowstride = pnmenc->info.width;
+    }
+    i_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (pnmenc->input_state, 0);
+
+    switch (GST_VIDEO_INFO_FORMAT (info)) {
+      case GST_VIDEO_FORMAT_RGB:
+      case GST_VIDEO_FORMAT_GRAY8:
+        for (i = 0; i < pnmenc->info.height; i++) {
+          index = i * i_rowstride;
+          for (j = 0; j < o_rowstride; j++, bytes++, index++) {
+            g_snprintf ((char *) omap.data + head_size, maxbytes_per_pixel,
+                format_str, imap.data[index]);
+            head_size += str_len;
+            omap.data[head_size++] = ' ';
+            /* Add new line so that file will not end up with single big line */
+            if (!((bytes + 1) % 20))
+              omap.data[head_size++] = '\n';
           }
-          break;
-        default:
-          GST_ERROR_OBJECT (encoder, "Unhandled format %s",
-              gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
-          gst_buffer_unmap (frame->output_buffer, &omap);
-          gst_buffer_unmap (frame->input_buffer, &imap);
-          g_free (header);
-          return GST_FLOW_ERROR;
         }
-    } else {
-      switch GST_VIDEO_INFO_FORMAT
-        (info) {
-        case GST_VIDEO_FORMAT_RGB:
-        case GST_VIDEO_FORMAT_GRAY8:
-          for (i = 0; i < pixels; i++) {
+        break;
+      case GST_VIDEO_FORMAT_GRAY16_BE:
+        for (i = 0; i < pnmenc->info.height; i++) {
+          index = i * i_rowstride;
+          for (j = 0; j < o_rowstride; j++, bytes++, index += 2) {
             g_snprintf ((char *) omap.data + head_size, maxbytes_per_pixel,
-                format_str, data.ui8[i]);
+                format_str, GST_READ_UINT16_BE (imap.data + index));
             head_size += str_len;
             omap.data[head_size++] = ' ';
-            if (!((i + 1) % 20))
+            /* Add new line so that file will not end up with single big line */
+            if (!((bytes + 1) % 20))
               omap.data[head_size++] = '\n';
           }
-          break;
-        case GST_VIDEO_FORMAT_GRAY16_BE:
-        case GST_VIDEO_FORMAT_GRAY16_LE:
-          for (i = 0; i < pixels; i++) {
+        }
+        break;
+      case GST_VIDEO_FORMAT_GRAY16_LE:
+        for (i = 0; i < pnmenc->info.height; i++) {
+          index = i * i_rowstride;
+          for (j = 0; j < o_rowstride; j++, bytes++, index += 2) {
             g_snprintf ((char *) omap.data + head_size, maxbytes_per_pixel,
-                format_str, data.ui16[i]);
+                format_str, GST_READ_UINT16_LE (imap.data + index));
             head_size += str_len;
             omap.data[head_size++] = ' ';
-            if (!((i + 1) % 20))
+            /* Add new line so that file will not end up with single big line */
+            if (!((bytes + 1) % 20))
               omap.data[head_size++] = '\n';
           }
-          break;
-        default:
-          GST_ERROR_OBJECT (encoder, "Unhandled format %s",
-              gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
-          gst_buffer_unmap (frame->output_buffer, &omap);
-          gst_buffer_unmap (frame->input_buffer, &imap);
-          g_free (header);
-          return GST_FLOW_ERROR;
         }
+        break;
+      default:
+        GST_ERROR_OBJECT (encoder, "Unhandled format %s",
+            gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
+        gst_buffer_unmap (frame->output_buffer, &omap);
+        gst_buffer_unmap (frame->input_buffer, &imap);
+        g_free (header);
+        return GST_FLOW_ERROR;
     }
+
+    gst_buffer_set_size (frame->output_buffer, head_size);
   } else {
-    /* Need to convert from GStreamer rowstride to PNM rowstride */
-    if (pnmenc->info.width % 4 != 0) {
-      if (pnmenc->info.type == GST_PNM_TYPE_PIXMAP) {
-        o_rowstride = 3 * pnmenc->info.width * bytesize;
-      } else {
-        o_rowstride = pnmenc->info.width * bytesize;
-      }
-      i_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (pnmenc->input_state, 0);
+    guint out_index = head_size;
 
-      for (i = 0; i < pnmenc->info.height; i++)
-        memcpy (omap.data + head_size + o_rowstride * i,
-            imap.data + i_rowstride * i, o_rowstride);
+    /* Binary output. 8-bit, or 16-bit BE */
+    if (pnmenc->info.type == GST_PNM_TYPE_PIXMAP) {
+      o_rowstride = 3 * pnmenc->info.width * bytesize;
     } else {
-      /* size contains complete image size inlcuding header size,
-         Exclude header size while copying data */
-      memcpy (omap.data + head_size, imap.data, (size - head_size));
+      o_rowstride = pnmenc->info.width * bytesize;
+    }
+    i_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (pnmenc->input_state, 0);
+
+    switch (GST_VIDEO_INFO_FORMAT (info)) {
+      case GST_VIDEO_FORMAT_GRAY16_BE:
+        for (i = 0; i < pnmenc->info.height; i++) {
+          index = i * i_rowstride;
+          for (j = 0; j < o_rowstride; j += 2, index += 2) {
+            guint16 val = GST_READ_UINT16_LE (imap.data + index);
+            GST_WRITE_UINT16_BE (omap.data + out_index, val);
+            out_index += 2;
+          }
+        }
+        break;
+      case GST_VIDEO_FORMAT_GRAY16_LE:
+        for (i = 0; i < pnmenc->info.height; i++) {
+          index = i * i_rowstride;
+          for (j = 0; j < o_rowstride; j += 2, index += 2) {
+            guint16 val = GST_READ_UINT16_LE (imap.data + index);
+            GST_WRITE_UINT16_BE (omap.data + out_index, val);
+            out_index += 2;
+          }
+        }
+        break;
+      default:
+        for (i = 0; i < pnmenc->info.height; i++) {
+          memcpy (omap.data + head_size + o_rowstride * i,
+              imap.data + i_rowstride * i, o_rowstride);
+        }
     }
   }
 
   gst_buffer_unmap (frame->output_buffer, &omap);
   gst_buffer_unmap (frame->input_buffer, &imap);
-  g_free (header);
 
   if ((ret = gst_video_encoder_finish_frame (encoder, frame)) != GST_FLOW_OK)
     goto done;